修改 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*
。
因此,即使在此程式中沒有明顯危險的構造,也會發生未定義的行為。