昨天寫《const 的迷思 (續)》時,重新審視了一下之前寫的文章,忽然想到了一個考驗編譯器的做法。

我在《const 的迷思》一文當中提到:

幾乎像樣一點的編譯器都可以自動 evaluate 常算式,然後在生成機器語言的時候變成 immediate value。 .....

那個理論上要額外建立的 const 常數既然派不上用場,所以編譯完就會徹底消失,根本就不會消耗執行時間和空間。唯一的例外是有人刻意凸顯 const 常數「可定址」這個特性,那麼編譯器才會不得不配置所需空間,但即便如此,其它不依賴此位址的程式碼還是會拿到 immediate value。

我不曉得其他人有沒有想過這個問題,這代表在語意上屬於同一個常數,有的程式碼得到的是 immediate value 型式,有的則是拿到一個存在特定位址的資料。於是我就想到,或許可以使用一些手段讓同一個常數的資料不一致。

秉持再忙也要抽時間惡搞的精神,下面這段程式碼不用三分鐘就誕生了

const int C = 10;
const int& refC = C;
int* ptrC = const_cast<int*>(&C);
*ptrC = 15;

cout << (&C == ptrC) << "\n";
cout << (C == *ptrC) << "\n";
cout << (C == refC) << "\n";

cout << C << "\n";
cout << *ptrC << "\n";
cout << refC << "\n";

和本山人的算計相同,g++ 4.2 和 VC2008 都產生出不正確的結果:
1
0
0
10
15
15

注意 (&C == ptrC)成立,但 (C == *ptrC) 卻不成立,這真是荒謬的錯誤。更好笑的錯誤還在後面,C 竟然不等於 refC!

由於編譯出來的結果和使用者表達的語意不同(嗯.....不過這的確是我預期的效果),所以可以算是編譯器的 bug。大家可以想像,如果自己的程式被這個 bug 害到會有多難抓。

結論是不要亂用 const_cast,否則連怎麼死都不曉得


補充

我查了一下 C++ standard 2003,似乎是這樣的

7.1.5.1
4 Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

所以事實上是編譯器愛怎麼搞隨它高興


novus 發表在 痞客邦 PIXNET 留言(1) 人氣()


留言列表 (1)

發表留言
  • damody
  • const_cast感覺是用在知道是不能改變,
    但是需要傳給沒加const的東西時用的= =
    感謝分享^^