V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iqoo
V2EX  ›  C++

C++ 用尽可能多的 const 是好风格吗?

  •  2
     
  •   iqoo · 2023-09-18 18:14:30 +08:00 · 4239 次点击
    这是一个创建于 422 天前的主题,其中的信息可能已经有所发展或是发生改变。

    之前写 TypeScript 时,习惯给能加 const 的变量都加上 const 。

    但 C++ 里加上 const 后代码累赘了不少。

    const auto v = .....
    
    const char* const buf = ....
    

    而且 STL 容器使用 const 修饰后,容器本身也不能修改了,而非只是变量不能改。

    所以 C++ 里加上尽可能多的 const 是不是一个好风格?

    第 1 条附言  ·  2023-09-18 20:00:39 +08:00

    要是有一个关键字能直接推导类型并定义成 const 就能更美观了。例如:

    #define let    const auto
    
    42 条回复    2023-09-21 17:08:07 +08:00
    macha
        1
    macha  
       2023-09-18 18:23:31 +08:00
    当然咯,只是很多人省事不加而已。
    wevsty
        2
    wevsty  
       2023-09-18 18:38:16 +08:00
    能用 const 的地方尽量使用 const 是一个好习惯,因为能避免意外的修改。
    对 STL 来说也是一样的,容器内部数据的变动很可能造成迭代器的失效或者多线程访问时出现各种各样的问题,如果确定一个地方不应该对容器内部数据进行修改,那么就应该鼓励传入 const 引用。
    当然,实际操作上还是得看具体的代码需求就是了。
    inhzus
        3
    inhzus  
       2023-09-18 18:39:17 +08:00
    大部分情况下、主流观点认为是是好风格(当然偶尔会看到一些也有道理的反驳观点)
    weeei
        4
    weeei  
       2023-09-18 18:41:19 +08:00
    只在关键的地方加也行,比如函数后面、局部指针变量,能够让编译器优化和避免一些低级错误。
    LuckyPocketWatch
        5
    LuckyPocketWatch  
       2023-09-18 18:42:57 +08:00
    @inhzus
    比如?
    xiangyuecn
        6
    xiangyuecn  
       2023-09-18 18:44:29 +08:00
    支持禁用 const 关键字。
    weeei
        7
    weeei  
       2023-09-18 18:48:52 +08:00
    比较操蛋的应该是 const int *p, int * const p, const int * const p; 的理解。
    Lightbright
        8
    Lightbright  
       2023-09-18 18:53:21 +08:00 via Android
    @weeei 什么年代了还在用传统指针 (逃
    agagega
        9
    agagega  
       2023-09-18 18:58:30 +08:00
    指针的情况,类型开头那个 const (表示指向的内容不可修改)没问题,后面的 const (表示指针本身不可修改),多数时候用不上,写起来也麻烦。因为编译器是能知道你的指针有没有被重新赋值的,大多数时候你也不需要这个约束。

    定义常量的话,用 const 当然也没问题,但 constexpr 可能更接近直观理解的那种「常量」。

    给方法末尾加 const 是好习惯,否则 const 对象就无法访问这些方法了。

    传参数的时候,传统意义上觉得写 const T&比较好,因为这样左值右值都能传,但如果你知道这个对象不是很大,直接按值传递 T 也是好的。

    C++这个 const 明显比各种对象语义的语言更好理解(先不考虑 mutable 和 const_cast 的话),一旦 const 就是整个都不能修改。
    weeei
        10
    weeei  
       2023-09-18 19:00:37 +08:00
    @Lightbright 网上很多正确使用 unique_ptr 、shared_ptr 和 weak_ptr 的文章,想用好不容易啊
    mainjzb
        11
    mainjzb  
       2023-09-18 19:00:51 +08:00   ❤️ 2
    是。所以 rust 默认是 const 的,除非你显示的写明 mut 才可修改。当然 C++不能这么来,历史代码不允许这样的改动。
    当然 C++还有 conprex ,能 conprex 的优先 conprex 情况变的更复杂(逃
    dart 稍微好点用 final 关键字等价于 const auto
    leonshaw
        12
    leonshaw  
       2023-09-18 19:08:58 +08:00 via Android   ❤️ 1
    应加尽加
    LuckyPocketWatch
        13
    LuckyPocketWatch  
       2023-09-18 19:41:33 +08:00
    @Lightbright
    去年接手过一段代码,是某个机床的输入设备的驱动代码,注释上的日期是 1982.06.。。。
    yalay
        14
    yalay  
       2023-09-18 19:59:28 +08:00
    flutter 就是各种 const ,当然对性能有好处的
    cnbatch
        15
    cnbatch  
       2023-09-18 20:00:02 +08:00
    喜欢加 const 那就加,无可厚非

    虽然我个人不喜欢动不动就 const
    lovelylain
        16
    lovelylain  
       2023-09-18 20:20:52 +08:00 via Android
    我一般只对必要的加 const ,例如函数参数列表或返回值里的 const 指针或引用,const 常量定义,const 成员方法,const 类型转换等。基本不会对值传递的参数加 const ,也很少用 const auto 去接收函数返回值,有时候会用 const auto&接收返回值。
    nullyouraise
        17
    nullyouraise  
       2023-09-18 22:58:40 +08:00
    我是习惯先加,报错时再去掉
    jaggerjiang
        18
    jaggerjiang  
       2023-09-18 23:09:27 +08:00
    rust 默认就是 const
    kneo
        19
    kneo  
       2023-09-18 23:14:06 +08:00 via Android
    你要是确定能行就加。
    就怕你自己稀里糊涂,今天加明天发现有代码编译不过去,还不知道得改哪儿。
    tool2d
        20
    tool2d  
       2023-09-18 23:50:05 +08:00   ❤️ 1
    现代编译器那么聪明( clang ),我觉得他应该比我更懂 const ,所以我选择不加。

    我以前也一直加,加到最后发现是给自己在设置编译障碍,干脆就不加了。
    leimao
        21
    leimao  
       2023-09-18 23:52:42 +08:00
    leimao
        22
    leimao  
       2023-09-18 23:56:13 +08:00
    const is also very useful in many different applications in practice, in addition to the optimizations from the compiler:
    https://leimao.github.io/blog/CPP-Const-Overloading/
    https://leimao.github.io/blog/CPP-Const-Iterator/
    leimao
        23
    leimao  
       2023-09-19 00:00:09 +08:00
    Also do not abuse define in C++.
    shaoyie
        24
    shaoyie  
       2023-09-19 00:21:35 +08:00
    你把写代码看作是写文章,主要是你要表达的主义要丰富,合理,恰到好处
    InvalidUsername
        25
    InvalidUsername  
       2023-09-19 00:32:00 +08:00 via Android
    是的,「 Effective C++」中 条款 03 就是:尽可能使用 const
    haohaolee
        26
    haohaolee  
       2023-09-19 01:18:01 +08:00
    如果找不到理由不加 const ,那就加。搜索 const correctness
    tyzandhr
        27
    tyzandhr  
       2023-09-19 01:30:04 +08:00 via Android
    谷歌风格指南里写,函数参数若不是传出值的指针,则必须写 const 。实际上我会尽可能用 constexpr 吧。
    dangyuluo
        28
    dangyuluo  
       2023-09-19 04:07:35 +08:00
    @tool2d 相反,编译器又笨又保守(in a sense),没有你的指示,根本不敢做任何优化。所以正确地使用`const`才能让编译器变聪明
    dangyuluo
        29
    dangyuluo  
       2023-09-19 04:13:13 +08:00
    比如在某个函数内,编译器无法保证其他进程不去改变`debug`这个 namespace scope 变量,就要傻傻地去生成 ASM 代码。加一条`bool debug_local = debug`就好了

    ```cpp
    for (int i = 0; i < n; i++) {
    ...
    if (debug) { // Global variable, can be possibly changed by printf
    printf("The data is NaN\n");
    }
    }
    ```
    nuk
        30
    nuk  
       2023-09-19 05:05:04 +08:00
    不加,从来不加,C 本来就是需要修改各种变量的,除在形参以外的 const 毫无意义。
    tool2d
        31
    tool2d  
       2023-09-19 09:29:17 +08:00
    @dangyuluo 这情况要加 volatile ,让编译器不优化这个局部变量。

    以前 gcc 很笨拙,毕竟那么多年的屎山。clang 不知道帮 gcc 填了多少坑。
    Evovil
        32
    Evovil  
       2023-09-19 09:48:17 +08:00
    就是因为经常有人讨论,加 const 是不是最佳实践
    才会出现 rust 这种完全不信任程序员的语言。。。
    araraloren
        33
    araraloren  
       2023-09-19 09:52:35 +08:00
    @nuk c is not c++
    yolee599
        34
    yolee599  
       2023-09-19 09:55:25 +08:00
    一些常量一般我都加 const ,比如查表法算 CRC 的表,接收到的指令和回调的映射表,字符串。还有函数参数只输入的,加 const 后就可以同时接收 const 和非 const 的变量,通用型更强。
    hazardous
        35
    hazardous  
       2023-09-19 10:30:03 +08:00
    不但变量加 const ,成员函数我现在都能加 const 都加 const 了
    dangyuluo
        36
    dangyuluo  
       2023-09-19 10:46:43 +08:00
    @tool2d `clang`在处理这个问题上是一样的,也是不敢贸然优化。不是 GCC 的锅。

    这里用 volatile 是错的思路。具体就不详细展开了,这有一篇很好的文章。
    https://liam.page/2018/01/18/volatile-in-C-and-Cpp/
    dangyuluo
        37
    dangyuluo  
       2023-09-19 10:48:42 +08:00
    不过可以理解,关于 volatile 有太多错误的“讲解”了,很多人理解都有问题
    dangyuluo
        38
    dangyuluo  
       2023-09-19 10:55:30 +08:00   ❤️ 1
    我突然想通你为什么说用 volatile 了,因为我们讨论的问题不是同一个。我指的是如果编译器能确定 loop 里的函数没有 side effect 后,可以执行 Loop unswitching 优化。Local const 变量可以做到这点

    https://en.wikipedia.org/wiki/Loop_unswitching

    你指的是如何用 volatile “禁止”编译器优化掉`if(debug)`,从而每次循环都去内存位置检查`debug`的 most-up-to-date 值
    lakehylia
        39
    lakehylia  
       2023-09-19 11:07:10 +08:00
    实际上,ide 会提示你加 const 更好。。。
    lotem
        40
    lotem  
       2023-09-19 18:03:27 +08:00
    能加 const 就加,是好的編碼習慣。卻不是好的風格。
    好的風格是,像某些其他語言那樣,變量綁定默認不可變。
    7B2fWg4Y9X
        41
    7B2fWg4Y9X  
       2023-09-20 11:36:35 +08:00
    const 具有传染性,除此之外都是提示和你协作的程序员或者是你自己的一种方法。如果和我协作的人能够清晰的知道自己要做什么,我不会加;如果是我自己开发我也不会加,除了这两种情况之外我会加 const
    Soora
        42
    Soora  
       2023-09-21 17:08:07 +08:00
    是个好风格,好处:
    1. 提升编译器优化空间, 可以看 csapp 第五章了解如何写出编译器友好的代码
    2. 提高可读性
    3. 防止意外修改
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3506 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 04:52 · PVG 12:52 · LAX 20:52 · JFK 23:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.