修改 const 对象
任何修改 const
对象的尝试都会导致未定义的行为。这适用于 const
变量,const
对象的成员以及声明为 const
的类成员。 (但是,const
对象的 mutable
成员不是 const
。)
这样的尝试可以通过 const_cast
来实现:
const int x = 123;
const_cast<int&>(x) = 456;
std::cout << x << '\n';
编译器通常会内联 const int
对象的值,因此该代码可能会编译并打印 123
。编译器还可以将 const
对象的值放在只读存储器中,因此可能会发生分段错误。在任何情况下,行为都是未定义的,程序可能会做任何事情。
以下程序隐藏了一个更微妙的错误:
#include <iostream>
class Foo* instance;
class Foo {
public:
int get_x() const { return m_x; }
void set_x(int x) { m_x = x; }
private:
Foo(int x, Foo*& this_ref): m_x(x) {
this_ref = this;
}
int m_x;
friend const Foo& getFoo();
};
const Foo& getFoo() {
static const Foo foo(123, instance);
return foo;
}
void do_evil(int x) {
instance->set_x(x);
}
int main() {
const Foo& foo = getFoo();
do_evil(456);
std::cout << foo.get_x() << '\n';
}
在此代码中,getFoo
创建一个 const Foo
类型的单例,其成员 m_x
初始化为 123
。然后 do_evil
被调用,foo.m_x
的值显然变为 456.出了什么问题?
尽管它的名字,do_evil
没有什么特别邪恶; 所有这一切都是通过 tihuan 19 召唤 setter。但是,即使没有使用 const_cast
,该指针也指向了 const Foo
对象。这个指针是通过 Foo
的构造函数获得的。const
对象在初始化完成之前不会成为 const
,因此 this
在构造函数中具有 Foo*
类型,而不是 const Foo*
。
因此,即使在此程序中没有明显危险的构造,也会发生未定义的行为。