[英]std::string s1 {“Modern C++”, 3} vs std::string s1 {str, 3}
[英]Difference between string += s1 and string = string + s1
我的一個程序在使用時超過了時間限制fans = fans + s[i]
,而當我使用fans += s[i]
它被接受了......為什么會發生這種情況? 為了解釋更多,fans 是一個字符串,s 也是一個字符串,所以在迭代字符串 si 時只需要 s 的一些字符,所以我正在創建一個新的字符串 fans。現在有兩種方法可以向我的新字符串添加字符粉絲。 問題在下面提到
fans = fans + s[i]; // gives Time limit exceeded
fans += s[i]; // runs successfully
對於內置類型a += b
與a = a + b
完全相同(除了a
只計算一次),但對於類,這些運算符被重載並調用不同的函數。
在您的示例中, fans = fans + s[i]
創建一個臨時字符串,並將其分配(移動)給fans
,但fans += s[i]
不會創建該臨時字符串,因此它可能會更快。
std::string
有成員operator +
和operator +=
。 前者通常通過中間臨時的方式與后者一起實現。 有效地看起來像這樣(如果您想確切地知道您的實現源,請檢查您的實現源):
/// note reference return type
std::string& operator +=(char c)
{
this->append(c);
return *this;
}
// note value return type
std::string operator +(char c) const
{
std::string tmp = *this;
tmp += c; // or just tmp.append(c) directly
return tmp;
}
tmp
的設置很昂貴。 整體功能可以(並且通常)通過移動分配語義在調用方的最終目的地變得更好,但臨時的費用仍然存在。 做幾次,你不會注意到差異。 這樣做數千次,或數百萬次,等等,這可能意味着一個不同的世界。
如果您使用fans=fans+s[i]
,則字符串將在每次循環中復制。 新元素將添加到字符串的副本中,結果將重新分配給變量fans
。 在此之后,必須刪除舊字符串,因為它不再被引用。 這需要花費大量時間。
如果您使用增強賦值fans+=s[i]
字符串將不會在每次循環中都被復制,並且不需要刪除引用變量,因為這里沒有引用變量。 這樣可以節省很多時間。
我希望你現在能理解!!
對於基本類型, a = a + b
和a += b
表示相同的意思。
對於任意的類類型, a = a + b
和a += b
是不相關的; 他們查找不同的運算符,這些運算符可以做任意的事情。 它們實際上無關的是代碼異味,這是設計問題的標志。
a = a + b
大致變成operator=( a, operator+( a, b ) )
; 實際的查找規則有點復雜(涉及成員運算符和非成員運算符,以及=
沒有非成員運算符等事實),但這就是它的核心。
a += b
在類似的意義上變成operator+=( a, b )
。
現在,在+=
方面實現+
是一種常見的模式; 如果你這樣做,你會得到:
a = a + b
變成
a = ((auto)(a) += b);
其中(auto)
是新的c++20 / c++23 “創建參數的臨時副本”功能。
從根本上說, a+=b
可以重用的內容a
直接,而a = a + b
不能; 在評估a+b
的那一刻,它不知道a
很快就會被覆蓋。
一些庫使用一種稱為“表達式模板”的技術來處理這個問題; a+b
不是值,而是表達式a+b
的編譯時描述,當分配給a
時,它實際上用於用數據填充a
。 使用表達式模板,消除了a+=b
比a=a+b
知道更多的基本問題。
現在,對於std::string
具體地, a+b
創建了一個臨時字符串對象,則a=(a+b)
移動到這a
(它可以重復使用臨時字符串對象的緩沖器或緩沖a
,標准為對此事保持沉默)。
a+=b
必須重用a
緩沖區中的任何多余容量。 所以如果你a.reserve(1<<30)
(10 億), a+=b
不能分配更多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.