気にしない。ループでそれを行う場合、文字列は常にメモリを事前に割り当てて再割り当てを最小限に抑えます- operator+=
その場合にのみ使用してください。そして、手動で行う場合は、このようなまたはより長いもの
a + " : " + c
次に、それは一時的なものを作成しています-たとえコンパイラが一部の戻り値のコピーを排除できたとしても。これは、連続して呼び出されるoperator+
と、参照パラメーターが名前付きオブジェクトを参照するか、サブoperator+
呼び出しから返される一時オブジェクトを参照するかがわからないためです。最初にプロファイルを作成する前に、心配する必要はありません。しかし、その例を見てみましょう。最初に括弧を導入して、バインディングを明確にします。わかりやすくするために使用する関数宣言の直後に引数を配置します。その下に、結果の式が何であるかを示します。
((a + " : ") + c)
calls string operator+(string const&, char const*)(a, " : ")
=> (tmp1 + c)
さて、その追加tmp1
で、示されている引数を使用したoperator +への最初の呼び出しによって返されたものです。コンパイラーは本当に賢く、戻り値のコピーを最適化することを想定しています。したがって、a
and の連結を含む1つの新しい文字列ができあがり" : "
ます。今、これが起こります:
(tmp1 + c)
calls string operator+(string const&, string const&)(tmp1, c)
=> tmp2 == <end result>
以下と比較してください。
std::string f = "hello";
(f + c)
calls string operator+(string const&, string const&)(f, c)
=> tmp1 == <end result>
一時的なものと名前付き文字列に同じ関数を使用しています!したがって、コンパイラは引数を新しい文字列にコピーして追加し、それをの本体から返す必要がありoperator+
ます。一時的な記憶を取り、それに追加することはできません。式が大きくなるほど、実行する文字列のコピーが多くなります。
次のVisual StudioとGCCは、c ++ 1xの移動セマンティクス(コピーセマンティクスを補完する)と右辺値参照を実験的な追加としてサポートします。これにより、パラメーターが一時的なものを参照しているかどうかを把握できます。これにより、上記のすべてがコピーなしの1つの「アドパイプライン」になるため、このような追加は驚くほど高速になります。
それがボトルネックであることが判明した場合でも、
std::string(a).append(" : ").append(c) ...
append
呼び出しはに引数を追加*this
して、自分自身への参照を返します。したがって、一時ファイルのコピーはそこで行われません。または、代わりにをoperator+=
使用することもできますが、優先順位を修正するために醜い括弧が必要になります。