罗剑锋的C++实战笔记
罗剑锋
奇虎360技术专家,Nginx/OpenResty开源项目贡献者
立即订阅
3815 人已学习
课程目录
已完结 30 讲
0/4登录后,你可以任选4讲全文学习。
课前导读 (2讲)
开篇词 | 把C++从“神坛”上拉下来,这次咱这么学
免费
课前准备 | 搭建实验环境
概论 (5讲)
01 | 重新认识C++:生命周期和编程范式
02 | 编码阶段能做什么:秀出好的code style
03 | 预处理阶段能做什么:宏定义和条件编译
04 | 编译阶段能做什么:属性和静态断言
05 | 面向对象编程:怎样才能写出一个“好”的类?
语言特性 (5讲)
06 | auto/decltype:为什么要有自动类型推导?
07 | const/volatile/mutable:常量/变量究竟是怎么回事?
08 | smart_ptr:智能指针到底“智能”在哪里?
09 | exception:怎样才能用好异常?
10 | lambda:函数式编程带来了什么?
标准库 (4讲)
11 | 一枝独秀的字符串:C++也能处理文本?
12 | 三分天下的容器:恰当选择,事半功倍
13 | 五花八门的算法:不要再手写for循环了
14 | 十面埋伏的并发:多线程真的很难吗?
技能进阶 (4讲)
15 | 序列化:简单通用的数据交换格式有哪些?
16 | 网络通信:我不想写原生Socket
17 | 脚本语言:搭建高性能的混合系统
18 | 性能分析:找出程序的瓶颈
总结篇 (5讲)
19 | 设计模式(上):C++与设计模式有啥关系?
20 | 设计模式(下):C++是怎么应用设计模式的?
21 | 知识串讲(上):带你开发一个书店应用
22 | 知识串讲(下):带你开发一个书店应用
期末测试 | 这些C++核心知识,你都掌握了吗?
结束语 (1讲)
结束语 | 路远,未有穷期
轻松话题 (4讲)
轻松话题(一) | 4本值得一读再读的经典好书
轻松话题(二) | 给你分享我的工作百宝箱
轻松话题(三) | 提高生活质量的App
轻松话题(四) | 真正高效的生活,是张弛有度
罗剑锋的C++实战笔记
15
15
1.0x
00:00/00:00
登录|注册

07 | const/volatile/mutable:常量/变量究竟是怎么回事?

罗剑锋 2020-05-21
你好,我是 Chrono。
上节课我讲了自动类型推导,提到 auto 推导出的类型可以附加 const、volatile 修饰(通常合称为“cv 修饰符”)。别看就这么两个关键字,里面的“门道”其实挺多的,用好了可以让你的代码更安全、运行得更快。今天我就来说说它们俩,以及比较少见的另一个关键字 mutable。

const 与 volatile

先来看 const 吧,你一定对它很熟悉了。正如它的字面含义,表示“常量”。最简单的用法就是,定义程序用到的数字、字符串常量,代替宏定义
const int MAX_LEN = 1024;
const std::string NAME = "metroid";
但如果我们从 C++ 程序的生命周期角度来看的话,就会发现,它和宏定义还是有本质区别的:const 定义的常量在预处理阶段并不存在,而是直到运行阶段才会出现
所以,准确地说,它实际上是运行时的“变量”,只不过不允许修改,是“只读”的(read only),叫“只读变量”更合适。
既然它是“变量”,那么,使用指针获取地址,再“强制”写入也是可以的。但这种做法破坏了“常量性”,绝对不提倡。这里,我只是给你做一个示范性质的实验,还要用到另外一个关键字 volatile。
// 需要加上volatile修饰,运行时才能看到效果
const volatile int MAX_LEN = 1024;
auto ptr = (int*)(&MAX_LEN);
*ptr = 2048;
cout << MAX_LEN << endl; // 输出2048
可以看到,这段代码最开始定义的常数是 1024,但是输出的却是 2048。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《罗剑锋的C++实战笔记》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(16)

  • 无止境
    c++的指针和引用有啥区别老师?

    作者回复: 简单来说,指针是内存地址,引用是变量别名,指针可以是空,而引用不能为空。

    2020-05-21
    2
    7
  • EncodedStar
    用好const 记住文章中的“ “const &”可以引用任何类型,是函数入口参数的最佳类型” 是重点

    作者回复: 这个是一个通用准则,但对于int、double这样小而简单的类型就有点“重”,int这样的内建类型可以直接用const T。

    Boost库里有一个call_traits,它可以推导出最佳类型。

    2020-05-22
    4
  • 陈英桂
    1、函数的入参,返回值还有变量的定义根据实际的情况,使用const来保证变量值只可以读,不可以修改。STL的迭代器也有const和非const,使用迭代器如果没有修改操作,尽量使用const版本的迭代器。
    2、函数的返回值总const,表示返回值只可以读

    作者回复:
    1.说的的很对。

    2.const返回值可以强制函数的调用者无法修改,让外界用起来更安全。

    2020-06-04
    1
  • 韩泽文
    我之前的理解好像与这个有偏差:
    const变量在未被优化时是分配到内存中,该内存页表标记为只读,不可写。 程序执行过程中尝试修改该内存就会页出错。
    同样的,const在编译阶段能够起到 安全作用,凡是同一个编译单元(同一个cc文件尝试修改它就会报错)
    上面提到的编译错误其实可以躲避编译器检查的,一般的定义时标注为const,另一cc文件引用时没有const,并且有修改操作,编译不报错的!
    以上是c语言的理解,不知道有没有问题,
    Cpp会对const变量符号修饰吗?

    作者回复: 我记得const最早是C++使用的,后来被借进了C。

    const常量其实就是变量,没有内存页标记这种机制,只是编译器会做检查,运行时不会有约束。

    2020-05-21
    1
  • 范闲
    1. effecttive里主要的用处就是const替换define,const成员函数,const &入参
    2.返回常量对象就是实际上保持了内部状态的不可变。不受外部影响,实际上也是不希望外部改变对象

    作者回复: 说的挺好的,其实在effective 里对const也花了很多的篇幅,用好const真的能够让代码更安全。

    2020-05-21
    1
  • 怪兽
    1. 常量的名称都是大写,但前面加k前缀表。这是什么风格?为什么是k?
    2. constexpr关键字是表示编译阶段的常量,而const表示运行时期的常量,只不过被编译器优化了,是这样理解吗?const和constexpr还有什么区别吗?

    作者回复:
    1,加k是有些公司的命名风格,k大概是const的简化吧。

    2.理解基本正确,constexpr还可以用在编译期计算,实现编译期函数、模板元编程。

    2020-07-09
  • Bluebuger
    volatile 在底层用的多,驱动、裸机开发这类。由于外部硬件设备,有部分处理器设计时候直接映射的内存地址,所以除了软件可以修改,硬件可能修改,所以需要让编译器不去优化这样的变量,必须从源头重新取值。

    作者回复: 对,volatile在底层开发的时候用的比较多,一般做上层应用开发、比如服务器、UI就很少用了。

    2020-06-17
  • itsiam
    给函数返回值加const, 返回常量对象,可以保证改实例的成员变量不被修改。

    作者回复: 对,这样外界用起来更加安全,给出去也放心。

    2020-06-10
  • 沉淀的梦想
    不太理解老师所说的 `const &` 万能引用,写了个 demo 发现编译不不过啊:

    ```
    int test(const int& any) {

    }

    int main() {
        int a = 2;
        // error: invalid conversion from ‘int*’ to ‘int’
        test(&a);
    }
    ```

    因为本人工作中写的语言不是 c++,出于兴趣来学习的,问题可能有点小白,老师见谅。

    作者回复: “万能引用”也要类型对才行,你的函数入口是const int&,而传入的是int*,这两个类型不匹配,那就肯定是不行的。

    C++对类型的检查比较严格,这方面确实还要再学习了解一下。

    2020-05-25
    3
  • 汪zZ
    突然发现是学长啊。
    感觉C++ Primer挺好的,如果看得过程中留意变量定义,会归纳出const的用法的,其实照着书上的例子好好的理解为什么用const,什么时候用,也就懂了。当然老师你归纳得也非常好。

    作者回复: 不知道是哪个学校的学弟,见笑了。

    const的用法比较零散,但又的确很重要,所以很有必要特别说一下。

    2020-05-24
  • xGdl
    对于const,存在常量折叠,老师所说的readonly非常到位,但对于const前后的*,只需要掌握类型的读取规则其实也就很简单《c++语法详解》,左结合优先即可。

    volatile修饰,阻止编译器优化,听说在msvc具有原子保证,而gcc不保证。

    作者回复:
    1.*const用法仔细阅读也能理解,但这需要花费不少力气,我希望的是代码尽量让人轻松阅读,不是所有人都能或者愿意掌握复杂的指针用法的。

    2.看C++应该看标准,尽量不要依赖编译器,volatile本身不具有原子性,应该用atomic库。

    2020-05-24
    1
  • silverhawk
    const 那个左右是遗传自C的那个左右法则,写代码时候也深恶痛绝,尤其是几层嵌套的const,最好加个括号一目了然。另外volatile也是经常需要跟硬件打交道的地方比较多,比如某个寄存器的值,可能程序不会修改但是被硬件中段信号修改,不过这些现在C++用不太到 了

    作者回复: 说的很好,我还见过const char * const * const,太可怕了。

    2020-05-23
  • 禾桃
    "它可以修饰引用和指针,“const &”可以引用任何类型,是函数入口参数的最佳类型"

    不太理解这个,能麻烦举个例子吗?

    谢谢!

    作者回复: int func(const T& x ),这样,无论x是什么类型,都可以接受,而且在函数体里不会被改变。

    2020-05-22
  • java2c++
    1.成员变量采用const代替宏定义define,功效有点类似于Java的final关键字,目的只是为了编译环节进行替换

    作者回复: 前半句说的比较对,后面我觉得有点问题。

    const常量不一定会在编译阶段做替换,这个不是标准里规定的,只是很多编译器都这么做来实现优化,不能把这种做法当成是必然。

    const常量还是应该理解成运行时只读的变量。

    2020-05-22
  • 蓝配鸡
    拿什么练手呢...工作中读C++较多, 写的少。

    作者回复: 读C++多,那可以试着自己改写优化一下这些代码。

    2020-05-21
    1
  • lckfa李钊
    在所有能使用const的地方使用const,增强代码的健壮性,使用多了,你未必看到它的好,但是它确实在那里发挥着作用,这样的回答有点人云亦云了。
    返回一个常量对象,最直接的作用是保证在函数返回时无法直接修改这个对象,比如 funcret()++ ,这种代码会在编译器失败,可以起到保护对象的作用。其他的好处需要老师指点下了

    作者回复: 说得挺好的。

    返回const对象,就能保证它是安全不会被改变的,限制了它的内外部影响。

    2020-05-21
收起评论
16
返回
顶部