修改 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*

因此,即使在此程式中沒有明顯危險的構造,也會發生未定義的行為。