ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

【C++ 面试真题】C++ 的 const 和 constexpr 有什么区别?

【C++ 面试真题】C++ 的 const 和 constexpr 有什么区别? 【C 面试真题】C 的 const 和 constexpr 有什么区别摘要const管能不能改只读语义constexpr管能不能在编译期算出来编译期常量。const变量可能运行期才确定值constexpr变量必须编译期可知且隐含constconstexpr函数可以双向运行——编译期输入得编译期结果运行期输入则退化为普通函数。本文用问答方式逐层拆解涵盖核心区别、经典误区、C11→C20 演进及面试高频追问。上期聊完static文末埋了个坑下期聊const和constexpr。这俩长得像、都跟常量沾边却是面试里最容易翻车的一对概念。很多同学张口就答const 是常量结果被一句const int n rand();合法吗直接带走。本文用问答的方式把它们一次掰扯清楚。一、先说结论❓ 说说 C 中的 const 和 constexpr 有什么本质区别✅ const和constexpr的本质区别概括起来就是const修饰的是只读语义——“我承诺不写它但不保证它是什么时候算出来的”constexpr修饰的是编译期可求值——“它的值必须在编译阶段就能算出来”。最小对比例子// 只读但值运行期才确定constintarand();// ❌ a 不能当编译期常量用// 编译期就能算出来constexprintb3*7;// ✅ b 21编译期常量a合法、但不是编译期可知b必须编译期可知。这就是全部差异的根。记一个口诀const 管能不能改constexpr 管能不能在编译期算出来。前者是访问权限后者是求值时机。一点历史背景const从 C 时代就有C 沿用并扩展原本就是只读的语义而constexpr是C11才引入的新关键字专门用来表达编译期常量。在constexpr出现之前C 程序员想定义编译期常量只能借助const加常量初始化这种约定俗成的写法语义含糊。constexpr的诞生就是要把编译期可知这件事明明白白地写出来让编译器替你把关——不满足就编译报错而不是留到运行期才发现。二、const 到底保证了什么❓ 那 const 真的等于常量吗✅ 不等于。const 保证的是只读不是编译期可知。看这个经典反例#includecstdlibintmain(){// 值运行期才确定constintnrand();// 之后只读没问题// n 10; // ❌ 编译错只读}n是 const合法——因为它初始化后不再改变。但它的值来自rand()编译器根本没法在编译期知道它是多少。后果是凡是要编译期常量的地方n都用不了// 设 const int n rand();std::arrayint,na;// ❌ 数组大小switch(x){casen:// ❌ case 标签break;}Tnobj;// ❌ 模板实参但反过来如果 const 变量恰好用常量表达式初始化它就同时也是编译期常量constintN10;// 常量表达式初始化intarr[N];// ✅ 可以当数组大小所以更准确的说法是const 是只读至于它是不是编译期常量要看它的初始化方式。再补一个容易混的细节const 修饰对象本身只读并不限制它的来源。它可以来自rand()、来自文件读入、来自函数返回值——只要初始化之后不再修改就满足 const 的契约。加分点const 的反义词不是变量而是mutable。它管的是访问权限只读不是值的来源时间。const 最实用的价值其实是契约——函数参数写成const T是在告诉调用方我不会改你的数据。顺带提一句在const成员函数里mutable成员仍可修改。这是 const 唯一的后门常用于缓存、互斥锁等逻辑上不影响对象状态的场景。三、constexpr 到底保证了什么❓ 那 constexpr 又保证了什么✅ constexpr 保证被它修饰的东西值能在编译期算出来。分两种用法。1. constexpr 变量——必须是编译期常量且必须立刻初始化、隐含 constconstexprintx10;// 编译期常量// x 5; // ❌ 隐含 const只读intbuf[x];// ✅ 可当数组大小2. constexpr 函数——“在给定编译期输入时能在编译期算出结果”constexprintsquare(intn){returnn*n;}intmain(){// 入参是编译期值constexprintasquare(5);// ✅ 25// 入参是运行期值intbsquare(rand());// ↑ 按普通函数在运行期跑}⚠️重点高频考点constexpr 函数不是只能在编译期跑。传入运行期值时它就退化成普通函数在运行期执行。它的语义是可以在编译期跑不是只能在编译期跑。这是一个非常大的理解误区。怎么判断这次调用到底在哪个阶段跑看接收结果的容器结果赋给constexpr变量、或用在static_assert、模板实参、数组大小里——编译器强制在编译期求值入参也必须是编译期值结果赋给普通变量——可以在运行期跑此时入参无所谓编译器自行决定要不要在编译期优化掉。一句话constexpr 函数是双向的跑在哪一端由调用点决定。四、核心区别对比表维度constconstexpr管什么只读语义编译期可求值求值时机运行期也行必须编译期可知运行期初始化✅ 允许❌ 禁止当数组/模板实参视初始化而定✅ 一定可以当 case 标签视初始化而定✅ 一定可以修饰函数❌ 不能✅ 可以是否互相蕴含不蕴含 constexpr变量隐含 const五、二者不是互斥而是可叠加❓ 那能同时写 const 和 constexpr 吗✅ 能但对变量来说写 constexpr 就够了——constexpr 变量隐含 const再写 const 是多余的constexprintx5;// 已隐含 constconstexprconstinty5;// ✅ 合法但多余真正常组合用的是和static用来在类里定义编译期常量classC{staticconstexprintk8;// C11类内可初始化// 但取地址仍需类外定义// C17constexpr 隐含// inline类外不必再写};指针这块最容易搞混。const T*和T* const是指向 const和const 指针的区别而constexpr 指针说的是指针本身是编译期常量跟它指向的对象是否 const无关intg1;// constexpr 修饰指针本身constexprint*pg;*p2;// ✅ 写 g合法// 注意指向的对象 g 非 const六、经典误区与陷阱❓ 实际写代码最容易踩哪些坑✅ 三个典型误区全是面试和实战的高发区。误区①把 const 当编译期常量constintszget_size();// 运行期值// int arr[sz]; // ❌ VLA// 应改用std::vectorintv(sz);// ✅ 运行期大小误区②以为 constexpr 函数必须编译期执行constexprintadd(inta,intb){returnab;}// 运行期调用完全合法intxadd(rand(),rand());// 不报错当普通函数跑误区③本该用 constexpr却写成 const白白丢优化// 前提factorial 是 constexprconstexprintfactorial(intn){returnn1?1:n*factorial(n-1);}constintvfactorial(5);// ⚠ 不保证编译期算可能留到运行期constexprintv2factorial(5);// ✅ 逼编译期算出来实操建议能加constexpr就加。它是超集——既能在编译期算优化、当常量又能在运行期跑。现代 C 鼓励把能在编译期算的东西都标成 constexpr。七、constexpr 函数的演进C11 → C20❓ constexpr 函数的限制是不是越来越松了✅ 对每个版本都在大幅放宽版本函数体里允许什么C11单条 return极简C14if / for / 局部变量C17if constexprC20new / try / string / vector加分点C20 起连std::string、std::vector都能在 constexpr 上下文里用了编译期计算的能力大涨。甚至能在编译期排序、做字符串处理。这也是为什么现在越来越多的库函数std::numeric_limits、std::vector的部分接口都加了 constexpr。八、面试高频追问Q1const 变量能当数组大小吗看初始化。const int N 10;✅ 可以编译期可知const int N f();❌ 不行运行期才知。Q2constexpr 函数在运行期调用结果还算常量表达式吗不算。只有当本次调用的入参都是编译期值时结果才是编译期常量否则它退化成普通函数结果就是运行期值。Q3const 和 constexpr 能同时写吗能。变量上constexpr 已隐含 const再加 const 多余。成员函数上二者正交完全可以同时出现例如constexpr int f() const;表示一个编译期可求值、且不修改对象的成员函数。Q4constexpr 函数能调用普通函数吗不能直接调用非 constexpr函数在编译期求值的路径上。C14 起可以自由调用其他 constexpr 函数。所以想让一个函数能在编译期用它调用的下游函数也得是 constexpr。Q5constexpr 变量能不初始化吗不能。constexpr 变量必须在声明处用常量表达式初始化否则编译报错——这跟 const 不一样const 可以只声明不初始化如extern const int n;。九、总结速查表特性constconstexpr本质只读编译期常量运行期初始化✅❌当数组/模板实参视初始化而定✅当 case 标签视初始化而定✅修饰函数❌✅修饰变量能否不初始化能不能互相蕴含不蕴含隐含 const一句话回顾const 管能不能改constexpr 管能不能在编译期算出来。前者是访问权限后者是求值时机——记住这一句再加一句constexpr 变量隐含 const、constexpr 函数也能在运行期跑这题就稳了。如果这篇对你有帮助欢迎收藏 。下期我们聊聊auto与decltype的那些坑敬请关注
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表