簡體   English   中英

關於移動活動對象存儲,C ++標准怎么說?

[英]What does C++ standard say about moving live object storage?

我對在當前的C ++標准下如何解釋以下情況感到好奇,尤其是在生命周期等方面。它是未定義的行為嗎?

首先,讓我們從以下定義開始:可重定位對象是在其實際存儲位置上不變的對象-也就是說,無論指針this的值如何,其狀態都保持不變。 假設我們有一個可重定位的類型Relocatable(它的定義與示例無關)。

然后我們有以下代碼(C ++ 17):

typedef std::aligned_storage_t<sizeof(Relocatable)> Storage;

// construct an instance of a relocatable within a storage
auto storage0 = new Storage();
new(storage0) Relocatable(...);

{ 
  // obj is a valid reference
  // should use std::launder() here, but clang doesn't have it yet
  Relocatable& obj = *reinterpret_cast<Relocatable*>(storage0);
}

// move the storage
auto storage1 = new Storage();
memcpy(storage1, storage0, sizeof(Storage));
delete storage0;

{ 
  // ?????? what does the standard say about this?
  Relocatable& obj = *reinterpret_cast<Relocatable*>(storage1);
}

它可以按預期與GCC和Clang一起使用(對象只是繼續存在於新存儲中)。 但是,我不能完全確定該標准是否可行。 從技術上講,對象的生存期尚未結束(未調用析構函數),並且在memcpy()調用之后,沒有任何訪問該對象的舊位置。 另外,不存在對舊位置的引用/指針。 盡管如此,鑒於C ++在大多數情況下似乎將對象標識和對象存儲視為相同的事物,因此可能有理由禁止這樣做。 在此先感謝您提出的所有深刻見解。

編輯:有人建議為什么對於不是TriviallyCopyable的對象,std :: memcpy的行為將是未定義的? 是這個問題的重復。 我不確定。 首先,我正在存儲,而不是對象實例。 其次,對於所有實際相關的應用程序, std::is_trivially_copyable<Relocatable>::value實際評估為true

附言:我問這個問題實際上有一個很好的實際原因。 有時,使對象只能存在於其容器中很有用-它們是不可復制且不可移動的。 例如,我目前正在設計具有此類屬性的優化樹數據結構-樹節點只能存在於樹存儲中,不能移出或復制它們-對它們的所有操作都是通過短期引用來執行的。 為了防止程序員犯錯誤(意外的復制/移動),我同時刪除了復制和move構造函數。 不幸的結果是無法將節點存儲在std :: vector中。 可以使用放置新的顯式管理的存儲來繞過此限制-但是,根據標准,我當然不願意做某些不可行的事情。

因此,與所有這些類型的問題一樣,僅在四種情況下創建對象:

當隱式更改聯合的活動成員([class.union])或創建臨時對象([conv.rval)時,將通過定義([basic.def]), new-expression創建對象。 ],[class.temporary])。

這段代碼:

auto storage1 = new Storage();
memcpy(storage1, storage0, sizeof(Storage));

storage1給您一個類型為Storage的對象,但是那時還沒有創建Relocatable類型的對象。 因此,這:

Relocatable& obj = *reinterpret_cast<Relocatable*>(storage1);

是未定義的行為。 期。


為了為此定義行為,我們需要第五種機制來創建對象,例如P0593中提出的內容

我們建議至少將以下操作指定為隱式創建對象:[...]

  • 調用memmove行為就像

    1. 將源存儲復制到臨時區域

    2. 在目標存儲中隱式創建對象,然后

    3. 將臨時存儲復制到目標存儲。

    這允許memmove保留普通復制對象的類型,或用於將一個對象的字節表示重新解釋為另一對象的字節表示。

  • 調用memcpy行為與調用memmove行為相同,不同之處在於它在源和目標之間引入了重疊限制。

該建議(或類似的建議)對於格式正確的代碼很有必要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM