簡體   English   中英

如何以未初始化的內存最好地處理復制交換習慣

[英]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.

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