簡體   English   中英

嘗試編寫可以從std :: string移動語義的字符串類

[英]Trying to write string class that can do move semantics from an std::string

我正在編寫自己的字符串類,僅僅是為了學習和鞏固一些知識。 我有一切工作,除了我想有一個使用移動語義與std :: string的構造函數。

在我的構造函數中,我需要復制並清空std :: string數據指針和其他東西,它需要保持空但有效狀態,而不刪除字符串指向的數據,我該怎么做?

到目前為止,我有這個

class String
{
private:
char* mpData;
unsigned int mLength;
public:
String( std::string&& str)
    :mpData(nullptr), mLength(0)
    {
    // need to copy the memory pointer from std::string to this->mpData

    // need to null out the std::string memory pointer
    //str.clear();  // can't use clear because it deletes the memory
    }
~String()
{
delete[] mpData;
mLength = 0;
}

沒有辦法做到這一點。 std::string的實現是實現定義的。 每個實現都是不同的。

此外,無法保證字符串將包含在動態分配的數組中。 一些std::string實現執行一個小的字符串優化,其中小字符串存儲在std::string對象本身內。

以下實現完成了所請求的內容,但存在一定風險。

關於這種方法的說明:

  • 它使用std :: string來管理分配的內存。 在我看來,像這樣分層分配是一個好主意,因為它減少了單個類試圖完成的事情的數量(但是由於使用了指針,這個類仍然存在與編譯器生成的副本相關的潛在錯誤操作)。

  • 我取消了delete操作,因為現在由allocation對象自動執行。

  • 如果使用mpData修改底層數據,它將調用所謂的未定義行為 它是不確定的,指示在這里 ,因為標准說,這是不確定的。 我想知道,如果有真實的實現,其中const char * std::string::data()行為與T * std::vector::data()行為不同 - 通過這些實現,這些修改將是完全合法的。 有可能通過data()進行的修改不會反映在后續的allocation訪問中,但基於此問題中的討論,這些修改似乎不太可能導致不可預測的行為,假設沒有通過allocation對象。

  • 它是否真的針對移動語義進行了優化 這可能是實現定義的。 它還可能取決於傳入字符串的實際值。 正如我在其他答案中所提到的,移動構造函數提供了一種優化機制 - 但它並不能保證優化會發生。


class String
{
private:
char* mpData;
unsigned int mLength;
std::string allocation;
public:
String( std::string&& str)
    : mpData(const_cast<char*>(str.data())) // cast used to invoke UB
    , mLength(str.length())
    , allocation(std::move(str)) // this is where the magic happens
    {}
};

我正在將這個問題解釋為“我可以使移動構造函數的結果成為正確的行為”而不是“我能否以最佳的速度使移動構造函數”

如果問題是嚴格的, “是否存在從std :: string竊取內部存儲器的可移植方式” ,則答案是“否,因為公共API中沒有提供'傳輸內存所有權'操作”


以下對移動語義的解釋引用了“移動構造函數”的一個很好的總結......

C ++ 0x引入了一種名為“rvalue reference”的新機制,除其他外,它允許我們通過函數重載檢測rvalue參數。 我們所要做的就是編寫一個帶有右值引用參數的構造函數。 在構造函數內部,只要我們將它保留在某個有效狀態,我們就可以對源執行任何操作。

基於此描述,在我看來,您可以實現“移動語義”構造函數(或“移動構造函數”),而無需實際竊取內部數據緩沖區。 一個示例實現:

String( std::string&& str)
    :mpData(new char[str.length()]), mLength(str.length())
    {
    for ( int i=0; i<mLength; i++ ) mpData[i] = str[i];
    }

據我了解,移動語義的關鍵是如果你願意 ,你可以更有效率。 由於傳入的對象是瞬態的,因此不需要保留其內容 - 因此竊取它們是合法的,但這不是強制性的。 也許,如果您沒有轉移某些基於堆的對象的所有權,那么實現這一點是沒有意義的,但它似乎應該是合法的。 也許它作為踏腳石是有用的 - 你可以盡可能多地竊取,即使這不是全部內容。

順便說一句,有一個密切相關的問題, 在這里 ,其中同種非標串的正在建設和包括的std :: string一個移動構造函數。 然而,類的內部結構是不同的,並且建議std :: string可以內部支持移動語義(std :: string - > std :: string)。

暫無
暫無

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

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