簡體   English   中英

我不能理解語義如何移動到std :: string

[英]I can't underestand how move semantics work to std::string

explicit Foo(std::string p_str) : m_str(std::move(p_str)) { ... }

完整的源代碼

我已經讓構造函數接受了帶有移動語義的參數。 p_str > m_str )為了更仔細地看,我打開了庫頭文件basic_string.h但是有一點我不明白。

basic_string(basic_string&& __str) noexcept :
         _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) {
     if (__str._M_is_local()) {
         traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1);
     } else {
         _M_data(__str._M_data());
         _M_capacity(__str._M_allocated_capacity);
     }

     _M_length(__str.length());
     __str._M_data(__str._M_local_data());  // (#)
     __str._M_set_length(0);
 }

這是basic_string類的move構造函數。 執行(#)后, p_str變為".\\000\\000\\000\\000\\000\\000\\000..." 據我所知, basic_string將字符串存儲在數組_M_local_buf ,方法_M_local_data()返回其地址。

然后,為什么要使用__str._M_data(__str._M_local_data()); p_str更改為零填充字符串? 是不是p_str__str )仍具有原始字符串?

您所看到的是短字符串優化。

libstdc ++的std::string實現有兩個位置可以存儲字符串數據。 它將長字符串存儲在動態分配的char數組中。 為了避免分配該數組的開銷,它還可以在通常用來跟蹤該動態分配的數組的大小的空間中存儲短字符串。 那是_M_local_data

_M_dataplus._M_p持有一個指向當前正在使用的哪個緩沖區的第一個元素的指針。 那是_M_data()返回的指針, _M_data(pointer)設置的_M_data(pointer)

所以放在一起,做

__str._M_data(__str._M_local_data());
__str._M_set_length(0);

告訴移出的字符串“忘記以前管理的任何緩沖區,開始使用本地緩沖區進行存儲,並假設您不保存任何數據”。


然后,為什么要使用__str._M_data(__str._M_local_data()); p_str更改為零填充字符串?

沒有。 它將p_str的數據指針更改為指向以前保持其外部分配數組大小的內存。 您看到的是該容量的剩余容量( p_str是否有46的偶然容量?這是'.'的ASCII代碼點)。 在這兩行之間的時刻, p_str處於不一致狀態。 它的大小仍然設置為以前的大小,但是它現在指向的緩沖區不包含該數量的字符。 當移動構造函數將其長度設置為0時,可以在下一行更正此錯誤。

您的std::string通過以下兩種方式之一存儲其內容:

  • 如果字符串較短,則將其直接存儲在_M_local_buf ,該std::string可能是std::string的數組成員(也可以通過_M_local_data()訪問)。
  • 如果字符串長,則將單獨分配一個char數組,並將其指針存儲在_M_p (也可以通過_M_data()訪問)。

if語句處理兩種可能的表示形式:

  • 如果內容直接存儲在std::string對象( __str._M_is_local() )中,則將數據復制到我們自己的_M_local_buf數組中。
  • 否則,我們只復制指針(由_M_data()返回)和容量。

    現在,我們的對象處於不一致狀態: this->_M_data()__str._M_data()指向同一分配的存儲; 他們都“擁有”它。 要解決這種情況,我們需要重置__str以便在銷毀字符串數據時不會嘗試將其從我們下面釋放出來。 我們將在一秒鍾內完成。

_M_length(__str.length()); __str復制長度值。

__str._M_data(__str._M_local_data()); 使_M_p指向__str對象的內部數組。 如果__str開頭不是短字符串,則此數組包含垃圾。 但這沒關系,因為:

__str._M_set_length(0)__str的長度重置為0 __str._M_local_buf的內容無關緊要,因為其中0個為“有效”,即字符串的一部分。

簡而言之:此move構造函數將__str的成員變量復制到我們的新對象中,然后使__str為空字符串。 (字符串內容已從__str “移動”到*this ,所以現在__str為空。)

這是一個基本原則:從變量移出會破壞其內容。 這將是一個有效的對象(在這種情況下為有效的std::string ),但是您不能依賴仍然存在的任何數據。

暫無
暫無

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

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