作爲學術練習,我創建了一個自定義向量實現,我希望支持複製非pod類型。如何最好地處理未初始化內存的可交換成語
我希望容器支持不提供默認構造函數的存儲元素。
當我爲向量保留內存,然後push_back一個元素(它管理它自己的資源並且實現了複製和賦值操作符 - 我忽略了當前的構造函數)我有一個使用copy-交換該類型的成語。
由於交換髮生在仍爲未初始化內存的類型上,所以在交換之後,被臨時調用的析構函數將嘗試釋放某些未初始化的數據,這當然會激化。
我可以看到幾種可能的解決方案。一種是確保所有非pod類型都實現默認構造函數,並在集合中的每個元素上調用該元素(放置新元素)。我不是這個想法的粉絲,因爲它看起來既浪費又麻煩。
另一種方法是在執行交換之前將容器中類型空間的內存mem設置爲0(這樣臨時值將爲空,調用析構函數將無誤地運行)。這對我來說有點不好意思,我不確定是否有更好的選擇(請參閱下面的代碼以獲得一個示例)。您也可以在爲一堆元素調用reserve後將所有保留空間memset設置爲0,但這可能是浪費。
是否有關於如何實現std :: vector的文檔,因爲調用reserve不會調用分配元素的構造函數,而resize會調用(並且對於未實現默認構造函數的構造函數,構造的臨時變量可以作爲第二個參數調用)
下面是一些代碼可以運行來演示問題,我省略了實際的向量代碼,但原理保持不變。
#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);
調用拷貝構造函數沒有賦值操作符!
謝謝!
我已經讀了幾次這個問題(可能是遲到了),但不清楚你是否有執行交換的自定義類型*或矢量*的問題? (順便說一句,我不認爲'memset()'會起作用)並且不清楚在單元化內存中使用copy-swap的原因(意味着你試圖訪問一個超出vector的「bounds」範圍的元素...) – Nim
嘿Nim!對不起,如果我的解釋不是很好,我會盡力澄清。基本上,在交換時,位於未初始化內存值的info_指針會被移入臨時進入該函數的臨時位置,然後當作用域結束時,該臨時對象會調用析構函數,但info_指針只是垃圾,所以調用delete []會導致崩潰。如果我以前memset內存,它將爲空,並且調用delete不起作用。我只想知道這是一件好事還是壞習慣。我想不出一個好的選擇:( – Tom
...但這意味着你*交換*的元素是*出界*(即超出矢量的*大小*) – Nim