3
std::string Concatenate(const std::string& s1,
                        const std::string& s2,
                        const std::string& s3,
                        const std::string& s4,
                        const std::string& s5)
{
    return s1 + s2 + s3 + s4 + s5;
}

デフォルトでreturn s1 + s2 + s3 + s4 + s5;は、次のコードと同等である可能性があります。

auto t1 = s1 + s2; // Allocation 1
auto t2 = t1 + s3; // Allocation 2
auto t3 = t2 + s4; // Allocation 3

return t3 + s5; // Allocation 4

割り当て時間を 1 に短縮するエレガントな方法はありますか? そのままにしておくということreturn s1 + s2 + s3 + s4 + s5;ですが、効率は自動的に改善されます。可能であれば、プログラマーによる の誤用を防ぐこともできますstd::string::operator +

ref-qualifierメンバー関数は役に立ちますか?

4

6 に答える 6

12

質問の前提:

s1 + s2 + s3 + s4 + s5 + ... + sn

n 個の割り当てが必要になりますが、正しくありません。

代わりに、O(Log(n)) の割り当てが必要になります。最初s1 + s1は一時的なものを生成します。その後、一時的な (右辺値) は、後続のすべての+操作の左側の引数になります。標準でstring +は、a の lhs が右辺値の場合、実装は単純にその一時ファイルに追加して移動することを指定しています。

operator+(basic_string<charT,traits,Allocator>&& lhs,
          const basic_string<charT,traits,Allocator>& rhs);

Returns: std::move(lhs.append(rhs))

この規格では、ストリングの容量が幾何学的に増加することも指定されています (1.5 から 2 の間の係数が一般的です)。したがって、すべての割り当てで、容量は幾何学的に増加し、その容量は一連の+操作に伝播されます。より具体的には、元のコード:

s = s1 + s2 + s3 + s4 + s5 + ... + sn;

実際には次と同等です:

s = s1 + s2;
s += s3;
s += s4;
s += s5;
// ...
s += sn;

幾何学的な容量の増加が短い文字列の最適化と組み合わされると、正しい容量を「事前予約」することの価値が制限されます。そのようなコードが実際にパフォーマンス テストでホット スポットとして表示される場合にのみ、私はわざわざそれを行います。

于 2014-09-10T00:49:21.457 に答える
1

次のようなコードを使用できます。

std::string(s1) + s2 + s3 + s4 + s5 + s6 + ....

これにより、名前のない単一の一時 (最初の文字列のコピー) が割り当てられ、それに他の文字列がそれぞれ追加されます。これらの関数はすべて一般にインライン化可能であるため、スマート オプティマイザーは、他のユーザーが投稿した予約 + 追加コードと同じコードにこれを最適化できます。

これは、(大まかに)次のように定義されている operator+ の移動拡張バージョンを使用して機能します。

std::string operator+(std::string &&lhs, const std::string &rhs) {
    return std::move(lhs.append(rhs));
}

RVO と組み合わせると、追加のstringオブジェクトを作成または破棄する必要がないことを意味します。

于 2014-09-10T00:19:01.037 に答える
0

これはどう:

std::string Concatenate(const std::string& s1,
                        const std::string& s2,
                        const std::string& s3,
                        const std::string& s4,
                        const std::string& s5)
{
    std::string ret;
    ret.reserve(s1.length() + s2.length() + s3.length() + s4.length() + s5.length());
    ret.append(s1.c_str());
    ret.append(s2.c_str());
    ret.append(s3.c_str());
    ret.append(s4.c_str());
    ret.append(s5.c_str());
    return ret;
}

2 つの割り当てがあり、1 つは構築するのに非常に小さく、もう 1 つはstd::stringデータ用にメモリを予約します。

于 2014-09-15T08:24:51.200 に答える