const
- 被
const
修饰的变量,不能对其进行赋值操作 - 但是,可以通过访问
const
对象的内存,对其进行修改
- 分析下面代码
int main(){ const int data = 10; int *p = const_cast<int*>(&data); *p = 20; std::cout << data << std::endl; //10 std::cout << *(&data) << std::endl; //20 return 0; }
- 以常量表达式初始化的
const
对象,编译器会将其出现的位置以其值替换 - 所以上面的代码,通过访问
data
的内存对其进行修改,但输出data
还是10;但其内存中的值确实被修改了
- 分析下面代码
int main(){ int val = 10; const int data = val; int *p = const_cast<int*>(&data); *p = 20; std::cout << data << std::endl; //20 std::cout << *(&data) << std::endl; //20 return 0; }
data
并非以常量表达式初始化,其初始值不能在编译器获取,所以编译器不会对其进行优化处理- 所以
const
对象,不应该以任何理由被修改,很可能因为编译器的优化,产生莫名其妙的bug
- 默认情况下,
const
对象只在当前文件类有效 - 为了使得其能在多文件共享,其在定义时也需要加上
extern
关键字/*file_1.cc*/ extern const int data = 10; /*file_2.cc*/ extern int data; int main(){ std::cout << data << std::endl; //10 return 0; }
constexpr
修饰变量
- 被
constexpr
修饰的变量,其必须以常量表达式初始化,且其具有const
属性/*file_1.cc*/ int val = 10; constexpr int data = val; //error 表达式必须含有常量值 /*file_2.cc*/ const int val = 10; constexpr int data = val; //正确,编译器优化将val替换为10 /*file_3.cc*/ int num = 10; const int val = num; constexpr int data = val; //error val并非以常量表达式初始化,所以其不能作为常量表达式
- 当
constexpr
修饰指针变量时,其只能作为顶层const
,且不能直接放在标识符前;同样的,其初始值必须是编译期可确定 - 如全局变量、静态变量、函数地址等,其地址属于编译期可确定的
int global = 10; int main(){ static int static_val = 10; //均正常编译 constexpr int *p_1 = &global; constexpr int *p_2 = &static_val; return 0; }
修饰函数
-
被
constexpr
修饰的函数,隐式被指定为inline
1 -
被
constexpr
修饰的函数,只有当遵循以下两点时,其才能作为常量表达式使用- 传入的实参和返回值都是常量表达式;其返回值类型可以是
void
,只要不被当作常量表达式使用,就不会报错 - 有且只有一个
return
constexpr int func(int arg){ int tmp = arg*arg; for(int i=0;i<5;i++) tmp *= arg; return tmp; } int main(){ constexpr int data = func(10); std::cout << data; //10000000 return 0; }
上面的情况,因为
func
比较简单,所以其被折叠,可以作为常量表达式但在下面这种情况,就不行了;非常不讲武德
constexpr int func(int arg){ int ret = arg; for(int i=0;i<10000;i++) for(int j=0;j<1000;j++) for(int k=0;k<100;k++) for(int l=0;l<10;l++) ret++; return ret; } int main(){ constexpr int data = func(10); //error 评估操作次数超过上限 std::cout << data; return 0; }
- 传入的实参和返回值都是常量表达式;其返回值类型可以是
-
且
constexpr
中定义的变量,无论其类型,必须初始化;但这并不意味着constexpr
中的变量具有const
属性这里就不上测试代码了,各位hxd自行实验
结语
const
和constexpr
细节较多,本文只做简述- 有任何错误评论区指正,共同进步
inline
只表示告诉编译器此函数可以被优化,并非让编译器优化 ↩︎