const 和 constexpr
const
const 修饰变量
无论const修饰全局还是函数的局部变量,那么该变量都不能被程序员显式的修改,否则编译器会报错。但是变量本质都是地址,因此可以对他取地址给指针,然后通过指针再去修改该值。这样操作编译器不会报错。例如:
1 | const int N = 1000; |
- 全局 const 变量:存储在只读存储区,使用上面的方法可以修改 会导致运行错误
- 函数局部的 const 变量:存在栈里,使用上面的方法修改它的值,且不会产生运行错误
c++ 对 const 会对默认类型的变量(非自定义的结构体成员变量,常规的int float 等会优化)在编译时期会优化,上面的例子中 会将所有地方的 N 像宏定义一样直接替换为 1000;例如
1 | cout << N << " " << *p; |
因此 推荐将变量定义为 const 类型 这样编译器会直接替换为值,后面就减少一次内存访问请求 相对宏定义的优势就是 有类型检查
const 类对象
定义 const 类对象 或者 结构体变量一样,代表他们的成员都不能被修改。并且,const 类对象只能调用它的 const 成员函数,而不能调用普通的非const成员函数。
const指针
- 一种指 指向的地址的内容不可以修改 但是它可以转而指向别的地址 (结合最开始的例子可以看出 编译器是通过 “指针的类型” 来判断是否只读的,因此如果普通指针指向const的变量地址,它的值仍然可以修改)
const int *p
- 指向的地址可以修改,但是它不能再指向别人
int * const p = &a
( 就看const 后面跟的是啥 啥就不能变)
const 成员函数
代表该成员函数 不能修改类中的成员变量,同时也正是这个特性,const 类的对象只能调用 ocnst 修饰的成员函数
constexpr
constexpr是C++11中新增的关键字,其语义是“常量表达式”,也就是在编译期可求值的表达式。最基础的常量表达式就是字面值或全局变量/函数的地址或sizeof等关键字返回的结果,而其它常量表达式都是由基础表达式通过各种确定的运算得到的。constexpr值可用于enum、switch、数组长度等场合。
编译时常量/常量表达式
- 必须是可以在编译阶段被识别的。比如模版的参数/数组的大小
- 例如 const int a = 5; 此时 5 就是一个常量表达式 sizeof() 就是个常量表达式 在编译时期就能确定 可以能用来初始化数组大小 case语句的分支等
1 | template <int N> |
特性
constexpr 在修饰函数的时候
- 如果函数的入口参数 是使用的字符常量,在编译时期可以确定 那么这个函数就是常量表达式 返回值可以直接用来初始化数组大小
- 如果入口参数的值编译时期无法直接确定 那么他就是个普通函数
constexpr的好处:
- 是一种很强的约束,更好地保证程序的正确语义不被破坏。
- 编译器可以在编译期对constexpr的代码进行非常大的优化,比如将用到的constexpr表达式都直接替换成最终结果等。
- 相比宏来说,没有额外的开销,但更安全可靠