const int a = 10;
const int* p1 = &a;
int* p2 = const_cast<int*>(p1);
*p2 = 20; // 通過非 const 指針修改
printf("%p: %d %p: %d %p: %d\n", &a, a, p1, *p1, p2, *p2);
// 輸出可能:0x...: 10 0x...: 10 0x...: 20
// 三個地址相同,但 a 仍為 10,*p1 為 10,*p2 為 20!
因 a 被聲明為 const int 並初始化為字面值,編譯器有權將其視為編譯期常量:
a 的所有讀取替換為 10(常量傳播)const 資格,允許寫入a 不變,繼續用 10 替換讀取C++ 標準明確規定:通過非 const 路徑修改原本定義為 const 的對象 → 未定義行為。表現包括但不限於:
-O0 vs -O2)行為不一致// 編譯器視角偽代碼
const int a = 10; // 編譯期常量,可能無內存實體
const int* p1 = &a; // 取地址迫使分配內存(或不分配,符號表記錄)
int* p2 = const_cast...; // 類型欺騙
*p2 = 20; // 實際寫入內存地址(若可寫)
printf("%d", a); // 常量傳播 → 直接輸出 10,不讀內存
printf("%d", *p1); // 可能讀內存(得 20),也可能常量傳播(得 10)
printf("%d", *p2); // 讀內存 → 20
關鍵點:a 的讀取被常量折疊優化掉了,而 *p1 和 *p2 是運行期間接訪問,無法在編譯期確定值。
mutablevolatile + 非 const,而非 const_castconst_cast 是拆除類型系統護欄的工具,而非修改常量的魔法。本例中:
a 讀取被優化為立即數「對 const 對象寫入,後果自負。」—— C++ 標準委員會