通过const_cast去除const后调用非const成员函数是否仅修改时触发UB?
问题
我想询问下述代码是仅当/* body */确实修改了i的值时才会触发未定义行为(UB),还是哪怕未进行修改,仅仅是对const对象调用非const成员函数maybeChange就会触发UB?
代码示例:
// header.hpp struct Foo { int i; void maybeChange(); }; void work(Foo const& foo);
// foo.cpp #include "header.hpp" void Foo::maybeChange() { /* body */ }
// work.cpp #include "header.hpp" void work(Foo const& foo) { const_cast<Foo&>(foo).maybeChange(); }
// main.cpp #include "header.hpp" Foo const foo{6}; int main() { work(foo); }
我理解当确实发生修改时会存在问题,因为这违反了编译器的合理假设——即全局对象foo不会被修改。但另一方面,C++标准中相关条款并未给出类似我上述示例的情况:通过const_cast去除const限定后对const对象调用非const成员函数但未实际修改对象的例子,仅给出了如下简单示例:
const int* ciq = new const int (3); // initialized as required int* iq = const_cast<int*>(ciq); // cast required *iq = 4; // undefined behavior: modifies a const object
其中最后一行确实修改了对象*ciq。
回答
仅当非const成员函数实际修改了const对象的内容时,才会触发未定义行为;如果只是调用非const成员函数但没有修改对象状态,并不会导致UB。
具体理由如下:
- C++标准对const对象的核心约束是禁止修改其内容,而非禁止调用非const成员函数。非const成员函数只是语法上具备修改成员的权限,但如果函数体未实际修改任何成员,就没有违反const对象的不可修改性。
- 编译器针对const对象的优化(比如将值视为常量缓存、省略读写操作等),只有当代码实际修改const对象时才会被打破,进而引发不一致的运行行为;若没有修改动作,这些优化不会产生问题。
- 标准给出的示例重点指向“修改const对象”这一行为本身,而非
const_cast或调用非const函数的动作——const_cast只是允许获取非const引用/指针,但后续是否触发UB完全取决于你用这个引用/指针执行了什么操作。
需要提醒的是:这种未修改的调用虽然本身合法,但属于极差的编码习惯。它会误导代码阅读者,且如果后续maybeChange的实现被修改为实际修改成员变量,就会悄无声息地引入未定义行为。
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

