[英]c++ operator associativity / string concatenation / move semantics
更新 :對不起,我錯了,二進制+
實際上是左關聯的。 但是盡管如此,這個問題仍然很重要,因為存在一個補充問題。
我在C / C ++中閱讀, +
運算符是右關聯的。 這意味着給定的std::string
s a, b, c
都初始化為某個非零長度,
string d = a + b + c;
應該完全等同於(即產生相同的可執行文件)
string d = a + (b + c);
現在,這似乎很不幸:將b
擴展a
b
然后再擴展a
c
更為合理。
string d = (a + b) + c;
因為應該在不需要重新分配的情況下使用b.size() + c.size()
復制操作來運行。
那么,我是否應該在實踐中使用parens / separate +=
分配,或者規范是否允許進一步優化以使無paren的版本同樣有效?
我在這里主要關注C ++ 11,也將不勝感激(盡管如此)關於移動語義等方面的文章。 如果這里適用。
一元運算 operator+
是右關聯的(就一元運算符而言),而二元 operator+
實際上是左關聯的。
要解決您的問題:
string d = a + b + c;
這首先將給出一個臨時結果(a+b)
。 暫時沒有辦法解決,因為a和b無法更改。 臨時文件將在內存中至少保留a.size()+b.size()
字節, a
和b
的內容將被復制到該新內存中。
然后將c
添加到臨時文件,並調用operator+(string&& lhs,const string& rhs)
。 這將占用臨時文件並在其中添加c
的內容,可能是在重新分配后以補償對更多空間的需求,並將a.size()+b.size()
字節從舊的內存復制到新的內存。 之后, c
的內容將被追加到新內存中的臨時文件中。
然后,move構造函數將開始執行操作,獲取臨時內存的所有權。
總共最多給出兩個(重新)分配(每個operator+
中一個),一個釋放(在tmp + c
中的重新分配期間)和四個副本(a,b,c,以及重新分配期間的臨時副本)。 沒有 a.size()+b.size()
復制操作,因為可以將字符串內容整體復制(memcpy / memmove),因為char數組是POD,不需要一個接一個地復制。
可以在此處優化的唯一事情是臨時預留足夠的內存來執行,而最終的結果a+b
。 盡管從語言/庫的角度來看,對此無能為力,但優化器從理論上可以看到分配和條件重新分配,並從一開始就通過保留足夠的內存來做正確的事情。 我不知道實現這種優化有多么容易,但是我想檢測string z = a + b + c + d + e + f...
的東西並不是那么容易,所以我不會指望它。
通常,臨時變量通常不會損害程序性能,因為這樣的字符串操作很少在關鍵性能的地方進行。
如果您絕對必須提高該操作的性能,則可以采用以下方法:
string d;
d.reserve(a.size() + b.size() + c.size());
d.append(a);
d.append(b);
d.append(c);
導致在預留呼叫期間進行一次分配,並精確分配了三個必要副本。
您將一元加號與加法混淆。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.