千家信息网

C++中const与constexpr的区别是什么

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,这篇文章主要讲解了"C++中const与constexpr的区别是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C++中const与constex
千家信息网最后更新 2026年11月04日C++中const与constexpr的区别是什么

这篇文章主要讲解了"C++中const与constexpr的区别是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"C++中const与constexpr的区别是什么"吧!

    一.const常量与#define比较

    define只是简单的替换,没有类型,const可以做到防窜改与类型安全。

    而且#define会在内存中可能(有几次替换就有几次拷贝)有多份拷贝,对于字面值常量加不加const都一样,例如:const char* arr = "123";,储存在常量区,只有一份拷贝;对于局部对象,常量存放在栈区,例如:void add(){const char crr[] = "123";},这里"123"本应储存在栈上,但编译器可能会做某些优化,将其放入常量区;对于全局对象,常量存放在全局/静态存储区;用const会比#define使用更少的空间,效率更高。

    这里有一个小例子:char* brr = "123"; char drr[] = "123";前者字符串123存在常量区,不能通过brr去修改"123"的值;后者"123"保存在栈区,可以通过drr去修改。

    现在C++除了一些特定用法,推荐用const,inline,enum等替换宏--来自《Effective C++》条款02

    二.const修饰

    1.修饰普通变量,必须初始化

    const int a = 10; 表示int对象a,是一个常量,不可以改变值,从编译器生成二进制角度看,生成的a存放在.rodata段,也就是只读(readonly)区域。不过并不绝对,有的时间统计优化等级开的高,也不取地址,可能会优化成立即数在.text段中。

    2.修饰类变量和成员变量

    class cAAA{public:    cAAA(int a) : m_iV(a){}    const int GetValue() const {return m_iV;}    void AddValueOneTime(){m_iChangeV++;}private:    const int m_iV;public:    mutable int m_iChangeV;    static const int m_iStaticV;};static const int m_iStaticV = 1000;const cAAA aa(100);aa.GetValue();aa.m_iChangeV++;
    • cAAA类成员m_iV是const变量,必须放到初始化列表中进行初始化,不能进行赋值。

    • 对于静态常成员,与普通静态成员类似,推荐放到类外.cpp中初始化。

    • aa只能调用const函数,如aa.GetValue(),不能调用非常成员函数aa.AddValueOneTime()。

    • 对于这种const对象,又想修改成员,可以在成员声明加上mutable,这样const对象aa也可以修改m_iChangeV,这种用法比较少。

    3.修饰成员函数

    • 表示这个函数可以被const对象调用,也可以被普通对象调用,不会改变对象的成员,也就是说更像一种只读不写型的逻辑运算,所以有些人推荐类成员函数,可以都加上const。有一个小技巧,当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复;但反过来不行,const函数内部也必须只能调用const函数-- 《Effective C++》条款03

    • 有一点要注意,编译器强制实施bitwase constness,但编写程序时应该使用conceptual constness,解决编译器的bitwase constness属性就用到了上述的mutable。关于介绍bitwase constness的具体表现可以参考《Effective C++》条款03。

    4.修饰指针

    const char* p1;char const *p2;char* const p3;const char* const p4;

    对于初学者来说这大概是很难理解的一个知识点,怎么区分这四个呢?记住秘诀,直接从右向左读就一招制敌了。

    • p1是一个指针,指向char字符常量,表示p1所指对象内容不可以改,所指地址可以改。

    • p2同p1,写法不同,两者等价。

    • p3是一个常量,且是个指针,指向char字符,表示p3所指对象内容可以改,所指地址不可以改。

    • p4是一个常量,且是个指针,指向char字符常量,表示p4所指对象内容不可以改,且所指地址也不可以改。

    • 相对来说p1,p2是最常用传参或者返回值的手段。

    5.修饰引用

    修饰引用和对象差不多,对象内容不可以改变。作为函数参数传参数,不存在copy开销,这是比较推荐的写法,例如:拷贝构造函数,赋值构造,STL里用于比较的函数或者仿函数,详情请参阅《Effective C++》条款20。bool Less(const cAAA& left, const cAAA& right);

    float dValue = 1.05f;const int& a = dValue;const int iTemp = dValue;const int& a = iTemp;

    因为常引用不能改变,这种情况下编译器会创建一个临时变量来处理隐式转换,我们实际是对临时变量进行了常引用。

    三.const转换

    一般来说,从T*转换到const T*是比较简单的,且编译器支持的隐式转换,也可以显示的用模板处理,例如我们简单写一下RemoveConst模板,最后用using化名一下。但从const T*到T*就麻烦一些,推荐使用const_cast。

    template struct RemoveConst{    typedef T Type;};template struct RemoveConst{    typedef T Type;};template using RCType = typename RemoveConst::Type;

    四.顶层const与底层const

    • 简单来说const修饰的对象本身不能改变就是顶层const,但如果是指针或者引用的对象不能改变,则称为底层const。

    • const int cV = 10; cV是顶层const,本身不能改变

    • char const *p2; p2是底层const,p2本身值可以改变,但所指内容不可以改变

    • char* const p3; p3是顶层const,p3的本身值不可以改变

    • const char* const p4; p4既是顶层const,又是底层const

    • 注:对于上述模板RCType是无法移除p2这种底层const,如果要移除,请用const_cast移除,但这种操作可能引起Crash或者未知风险

    const char* pA = "sss";char* pB = const_cast(pA);auto pC = RCType(pA);std::cout << "type is the same: " << std::is_same::value << std::endl;std::cout << "pB Type Name: " << typeid(pB).name() << "pc Type Name: " << typeid(pC).name() << std::endl;//pB[0] = 'A';//error, Segmentation fault

    五.C++11新引入的constexpr

    这个关键字表示这是一个常量表达式,是一个编译期就可以确认的值,最常用于模板中,例如模板递归求值。

    它可不只是变量,例如:

    const int iSize1 = sizeof(int);const int iSize2 = GetSize();

    iSize1是个常量,编译期的,但iSize2就不一定,它虽然不能改变,但要到GetSize()执行结束,才能知道具体值,这与常量一般在编译期就知道的思想不符,解决这个问题的方法就是改为:constexpr int iSize2 = GetSize(); 这样要求GetSize()一定要能在编译期就算出值,下面几个例子中GetSizeError()就会编译失败。GetFibo函数,编译期就已经递归计算出值。

    constexpr int GetSize(){  return sizeof(int) + sizeof(double);}constexpr int GetSizeError(){  return random();}constexpr int GetCalc(int N){  return N <= 1 ? 1 : N * GetCalc(N - 1);}const int iSize1 = sizeof(int);constexpr int iSize2 = GetSize();//constexpr int iSize3() = GetSizeError();constexpr int iSize4 = GetCalc(10);std::cout << iSize1 << " " << iSize2 << " " << iSize4 <

    当然我们可以用模板写GetCalc函数:

    template struct TCalc{  static constexpr int iValue = N * TCalc::iValue;};template <>struct TCalc<1>{  static constexpr int iValue = 1;};std::cout << TCalc<10>::iValue << std::endl;

    感谢各位的阅读,以上就是"C++中const与constexpr的区别是什么"的内容了,经过本文的学习后,相信大家对C++中const与constexpr的区别是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

    对象 常量 函数 编译 成员 C++ 内容 变量 所指 模板 编译器 底层 指针 顶层 推荐 地址 字符 拷贝 条款 普通 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 奇酷互联网科技 互联网科技股票 深圳天众互联网科技公司 长亮科技互联网金融 互联网科技公司做什么 丰台科技园 互联网公司 银川新华互联网科技学校地址 互联网汽车科技小镇 天速互联网络科技有限公司 深圳国际航运科技和互联网 欧洲十大科技互联网公司 现代互联网科技股 互联网大会黑科技排名 苏州五指互联网络科技有限 无锡工业互联网科技有限公司 元气玛特互联网科技公司是外包吗 启辰互联网科技 2021世界互联网领先科技成果发布 西安有哪些互联网高科技企业 互联网 科技节活动 微视频大赛 互联网中国科技 广州互联网络科技有限公司 西安互联网科技公司 互联网实体化科技化 剑昆互联网络科技有限公司临桂 广州恒生互联网科技有限 宜昌元轩互联网科技有限公司 黑云互联网科技有限公司 杭州披云加互联网科技有限公司 恒生互联网科技趋势
    0