2

私のプロジェクトでは、次のような機能があります。

bool VectorList::put(const Pair &p);

これにより、がコピーされて に追加Pairされます。VectorListPair

次のように使用できます。

Pair p { "key", "value" };

VectorList v;
v.put(p);

// or
v.put(Pair{ "anotherkey", "anothervalue" });

ただし、2番目のケースでは不要なオブジェクトが作成されるため、やりたい

bool VectorList::put(Pair &&p);

これがベクター(gcc、llvm)でどのように行われるかを確認しましたが、 equal / std::move() 行を除いて、両方のメソッドに100%同じコードがあります。

コードを複製せずにそれを行う方法はありますか?


put()これに似ています:

struct Node{
    Pair pair;
    AdditionalThings at;
};

bool VectorList::put(const Pair &p){
    if (not_good_for_insert(p))
         return false;
    // ...
    Node node = create_node();
    node.pair = p;
    // ...
    return true;
}
4

3 に答える 3

7

はい、完全転送を使用します:

template <typename P>
bool VectorList::put (P &&p) {
    //can't forward p here as it could move p and we need it later
    if (not_good_for_insert(p)) 
     return false;
    // ...
    Node node = create_node();
    node.pair = std::forward<P>(p);
    // ...
    return true;
}

別の可能性は、マキシムの回答のように値を渡すことです。完全転送バージョンの利点は、互換性のある引数を渡せば中間変換が不要であり、移動にコストがかかる場合にパフォーマンスが向上することです。欠点は、転送参照関数が非常に貪欲であるため、他のオーバーロードが意図したとおりに動作しない可能性があることです。

Pair &&pはユニバーサル参照ではなく、単なる右辺値参照であることに注意してください。ユニバーサル (または転送) 参照には、テンプレート引数のように、推測されたコンテキストで右辺値が必要です。

于 2015-09-25T08:54:05.457 に答える
2

TartanLlamaがアドバイスするように、理想的な解決策は普遍的な参照を受け入れることです。

ヘッダー ファイルに関数定義を含める余裕がある場合は、理想的なソリューションが機能します。関数定義をヘッダーで公開できない場合 (たとえば、Pimpl イディオムまたはインターフェイス ベースの設計を採用している、または関数が共有ライブラリに存在する場合)、2 番目に良いオプションは値で受け入れることです。このようにして、呼び出し元は引数の作成方法 (コピー、移動、均一な初期化) を選択できます。ただし、呼び出し先は 1 回の移動の料金を支払う必要があります。例bool VectorList::put(Pair p);:

VectorList v;
Pair p { "key", "value" };
v.put(p); 
v.put(std::move(p));
v.put(Pair{ "anotherkey", "anothervalue" });
v.put({ "anotherkey", "anothervalue" });

そして実装では、引数から移動します:

bool VectorList::put(Pair p) { container_.push_back(std::move(p)); }

もう 1 つのコメントは、コンテナー操作の標準 C++ 名 ( などpush_back/push_front) を使用して、それが何をするかを明確にすることです。putあいまいであり、コードの読者がソース コードまたはドキュメントを調べて、何が起こっているのかを理解する必要があります。

于 2015-09-25T08:55:56.777 に答える