3

我正在編寫自己的字符串類,僅僅是爲了學習和鞏固一些知識。我有一切工作,除了我想有一個使用移動語義與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; 
} 
+0

相關問題:http://stackoverflow.com/questions/9957840/move-string-into-vector – nobar 2012-09-22 22:54:02

回答

7

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

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

+0

所以這是不可能的?在不同類型的類之間進行移動語義通常是一個糟糕的主意? stl如何在向量類的字符串中管理它? – EddieV223 2012-07-28 04:23:05

+5

'vector '只需要能夠從另一個「字符串」移動構造或移動分配一個「字符串」。 'string'類通過它的移動構造函數和移動賦值操作符來處理它。跨類型移動有點奇怪,但如果你控制源類型和目標類型的實現,或者源類型提供了某種方式從中移動(例如'unique_ptr'提供'release'成員函數) 。 – 2012-07-28 04:25:23

+0

我真的很討厭總結性結論「不行」。 C++爲您提供了很多控制權,並且有狀態的分配器至少可以爲通用的'std :: basic_string'情況進行管理。它只需要記住分配的塊(假設一個'basic_string'沒有擁有堆中的多個塊),而自定義的'move'-只需要在清除之前通知它所有權的變化'basic_string'。 – Potatoswatter 2012-07-28 16:25:30

-1

我解釋了一個問題,「我可以在正確的行爲,此舉構造結果」而不是「我可以讓移動構造函數優化快」

如果問題是嚴格的,「有沒有竊取的std :: string內部存儲器的便攜式辦法」,那麼答案是「沒有,因爲在沒有提供任何‘轉讓記憶所有權’操作公共API「


this explanation of move semantics下面的報價提供了「移動構造」的一個很好的總結...

的C++ 0x引入了一個叫做「右值引用」,除其他事項外 新機制,允許我們通過函數 重載來檢測右值參數。我們所要做的就是編寫一個具有右值 引用參數的構造函數。在構造函數內部,只要我們將它放在某個有效狀態,我們就可以做任何我們想要的源代碼。

基於這個描述,在我看來,你可以實現「移動語義」構造函數(或「移動構造函數」)而不必強制實際竊取內部數據緩衝區。 的範例:

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

據我瞭解,移動語義的一點是,如果你想你可以更有效。由於傳入的對象是暫時的,它的內容不需要保存 - 所以盜取它們是合法的,但它不是強制性的。也許,如果你沒有轉移一些基於堆的對象的所有權,那麼實現這一點就沒有意義,但它看起來應該是合法的。也許它作爲一個墊腳石是有用的 - 即使這不是全部內容,也可以儘可能多地竊取。

順便說一句,有一個密切相關的問題here其中正在構建相同種類的非標準字符串,幷包括std :: string的移動構造函數。然而,類的內部是不同的,並且建議std :: string在內部可能內置了對移動語義的支持(std :: string - > std :: string)。

+0

如果您沒有移動動態內存,那麼只需使用參考。此外,根據類的實現,您的代碼可能需要一個空終止符。字符串(std :: string&str) – EddieV223 2012-07-28 05:21:09

+0

他正在嘗試做更多*而不是移動語義允許的,而不是更少。 – 2012-07-28 05:44:29

+0

我發現這個博客文章同意我的回答:http://akrzemi1.wordpress.com/2011/08/30/move-constructor-qa – nobar 2012-07-28 15:32:42

1

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

注意對這種做法:

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

  • 我廢除了delete的操作,因爲該操作現在由allocation對象自動執行。

  • 它會調用所謂的未定義的行爲如果使用mpData修改底層數據。它是未定義的,如here所示,因爲標準說它是未定義的。不過,我想知道,如果存在const char * std::string::data()的行爲與T * std::vector::data()不同的真實世界的實現 - 通過這些實現,這樣的修改將是完全合法的。通過data()進行的修改可能不會反映在後續訪問allocation中,但基於this question的討論,假設通過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 
    {} 
}; 
相關問題