[英]How to best handle copy-swap idiom with uninitialised memory
在學術活動中,我創建了一個自定義矢量實現,以支持非Pod類型的復制。
我希望容器支持不提供默認構造函數的存儲元素。
當我為向量保留內存,然后push_back一個元素(它管理它自己的資源並實現了復制和賦值運算符-我現在暫時忽略了移動構造函數)時,我會遇到使用復制交換習慣的問題類型。
因為交換發生在仍未初始化的內存類型上,所以在交換之后,為臨時調用的析構函數將嘗試釋放一些未初始化的數據,這些數據當然會崩潰。
我可以看到一些可能的解決方案。 一種是確保所有非Pod類型都實現一個默認構造函數,並在集合中的每個元素上調用(放置新的)。 我不喜歡這個想法,因為它既浪費又麻煩。
另一個方法是在進行交換之前將容器中該類型空間的內存設置為0(這樣,臨時變量將為null,並且調用析構函數的操作將不會發生錯誤)。 不過,這對我來說有點hacky,我不確定是否有更好的選擇(請參見下面的代碼以獲取示例)您也可以在為一組元素調用reserve之后將所有保留空間設置為0,但是再次,這可能是浪費的。
是否有關於std :: vector的實現方式的文檔,因為調用儲備將不會調用已分配元素的構造函數,而調整大小會(對於未實現默認構造函數的類型,可將構造的臨時變量作為第二個參數傳遞給調用)
下面是一些可以運行以演示該問題的代碼,我省略了實際的矢量代碼,但原理保持不變。
#include <iostream>
#include <cstring>
// Dumb example type - not something to ever use
class CustomType {
public:
CustomType(const char* info) {
size_t len = strlen(info) + 1;
info_ = new char[len];
for (int i = 0; i < len; ++i) {
info_[i] = info[i];
}
}
CustomType(const CustomType& customType) {
size_t len = strlen(customType.info_) + 1;
info_ = new char[len];
for (int i = 0; i < len; ++i) {
info_[i] = customType.info_[i];
}
}
CustomType& operator=(CustomType customType) {
swap(*this, customType);
return *this;
}
void swap(CustomType& lhs, CustomType& rhs) {
std::swap(lhs.info_, rhs.info_);
}
~CustomType() {
delete[] info_;
}
char* info_;
};
int main() {
CustomType customTypeToCopy("Test");
// Mimics one element in the array - uninitialised memory
char* mem = (char*)malloc(sizeof(CustomType));
// Cast to correct type (would be T for array element)
CustomType* customType = (CustomType*)mem;
// If memory is cleared, delete[] of null has no effect - all good
memset(mem, 0, sizeof(CustomType));
// If the above line is commented out, you get malloc error - pointer
// being freed, was not allocated
// Invokes assignment operator and copy/swap idiom
*customType = customTypeToCopy;
printf("%s\n", customType->info_);
printf("%s\n", customTypeToCopy.info_);
return 0;
}
任何信息/建議將不勝感激!
解決了!
感謝@Brian和@Nim幫助我了解分配(復制/交換)有效時的用例。
為了實現我想要的功能,我只需要替換生產線
*customType = customTypeToCopy;
同
new (customType) CustomType(customTypeToCopy);
調用復制構造函數而不是賦值運算符!
謝謝!
您不使用復制和交換進行構造。
您可以使用復制和交換進行分配,以解決以下問題:分配的左側是已初始化的對象,因此在將右側的狀態復制或移入其中之前,它需要釋放其持有的資源。 ; 但是如果復制或移動構造因引發異常而失敗,則我們希望保留原始狀態。
如果您要進行構造而不是分配-因為目標未初始化-不存在通過復制和交換解決的問題。 您只需使用new位置調用構造函數。 如果成功,那就太好了。 如果它因拋出異常而失敗,則該語言保證已破壞的所有子對象都被銷毀,而您只需讓異常向上傳播; 在失敗的情況下,目標的狀態將與之前相同:未初始化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.