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