[英]Why introduce `std::launder` rather than have the compiler take care of it?
我剛讀過
坦率地說,我只是摸不着頭腦。
讓我們從@NicolBolas 接受的答案中的第二個例子開始:
aligned_storage<sizeof(int), alignof(int)>::type data; new(&data) int; int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life]/8 告訴我們,如果你在舊的存儲中分配一個新的 object,你不能通過指向舊的指針訪問新的 object。
std::launder
允許我們避開它。
那么,為什么不直接更改語言標准,以便通過reinterpret_cast<int*>(&data)
訪問data
是有效/適當的呢? 在現實生活中,洗錢是一種向法律隱瞞現實的方式。 但我們沒有什么可隱瞞的——我們正在做一些完全合法的事情。 那么,當編譯器注意到我們正在以這種方式訪問data
時,為什么它不能將其行為更改為其std::launder()
行為呢?
關於第一個例子:
X *p = new (&u.x) X {2};
因為 X 是微不足道的,我們不需要在創建新的 object 之前銷毀舊的 object,所以這是完全合法的代碼。 新的 object 的 n 成員將為 2。
那么告訴我...
uxn
會返回什么?顯而易見的答案是 2。但這是錯誤的,因為允許編譯器假定一個真正的
const
變量(不僅僅是一個 const&,而是一個聲明為const
的 object 變量)永遠不會改變。 但我們只是改變了它。
那么為什么不讓編譯器不允許我們在寫這種通過指針訪問常量字段的代碼時做出假設呢?
為什么使用這個偽函數來在形式語言語義中打個洞是合理的,而不是根據代碼是否執行這些示例中的操作來將語義設置為它們需要的樣子?
取決於代碼是否在這些示例中執行類似操作
因為編譯器不能總是知道何時“以這種方式”訪問data
。
按照目前的情況,允許編譯器假設以下代碼:
struct foo{ int const x; };
void some_func(foo*);
int bar() {
foo f { 123 };
some_func(&f);
return f.x;
}
bar
將始終返回 123。編譯器可能會生成實際訪問 object 的代碼。 但是 object model不需要這個。 fx
是const
object (不是const
的引用/指針),因此不能更改。 並且f
必須始終命名相同的 object (實際上,這些是您必須更改的標准部分)。 因此, fx
的值不能通過任何非 UB 方式改變。
為什么有這個偽函數在形式語言語義上打一個洞是合理的
這其實是討論過的。 該論文提出了這些問題已經存在多長時間(即:自 C++03 以來),並且經常使用 object model 實現的優化。
該提案被拒絕,理由是它實際上無法解決問題。 從這次旅行報告中:
然而,在討論過程中發現,提議的替代方案無法處理所有受影響的場景(特別是 vtable 指針正在發揮作用的場景),並且沒有獲得共識。
該報告沒有就此事提供任何具體細節,相關討論也未公開。 但是提案本身確實指出它不允許對第二個虛擬 function 調用進行去虛擬化,因為第一個調用可能已經構建了一個新的 object。 因此,即使是 P0532 也不會使launder
變得不必要,只是不太必要。
我采取相反的方法。 我不喜歡 c++ 像這樣玩弄 memory 或者至少允許你玩。 當嘗試創建新的 object 和包含常量值或 object 但具有 const 成員的地址時,編譯器應拋出錯誤。 如果程序員說 const 就是 const。 對不起。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.