簡體   English   中英

c ++運算符關聯性/字符串連接/移動語義

[英]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()字節, ab的內容將被復制到該新內存中。

然后將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.

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