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