6

それで、昨日 youtube で C++ のビデオを見ていたら、C++-11 の右辺値参照と移動セマンティクスに関するものに出会いました。大まかな概念は理解していると思いますが、今日 TA でコードを調べていたときに、std::pair<HostName, IPAddress>& p以下のコードで参照 ( など) を使用しなかった理由を尋ねられました。この場合は全く考えていなかったのですが、聞いてみると「C++-11では一般的に値渡しを使うべき」という動画があったのを思い出しました。

したがって、私の質問は次のとおりです。以下のコードでは、好きかどうかstd::pair<HostName, IPAddress> pの方が良いでしょうか? std::pair<HostName, IPAddress>& p移動セマンティクスが使用される予定はありますか?それによって違いが生じるでしょうか?

IPAddress NameServer::lookup( const HostName& host ) const {
    auto it = std::find_if( vec.begin(), vec.end(),
                       [host] ( std::pair<HostName, IPAddress> p ) {
        return p.first == host;
    } );
    ...
}
4

1 に答える 1

10

この場合、const参照渡しする必要があります。値による受け渡しは、渡された値のコピーまたは移動を最終的に生成する場合に意味があります。コピーも移動もしたくない、特にだけ見constたい場合は ( ) 参照で渡します。

ここで、ラムダ述語は、入力で受け取ったペアのコピーを生成する必要はありません。したがって、値で渡す (またはvaueでキャプチャする) 理由はありません。

IPAddress NameServer::lookup( const HostName& host ) const {
    auto it = std::find_if( vec.begin(), vec.end(),
        [&host] ( std::pair<HostName, IPAddress> const& p ) {
    //   ^^^^^                                   ^^^^^^
        return p.first == host;
    } );
    ...
}

代わりに、次のケースを考えてみましょう (典型的な C++03 コード):

struct A
{
    A(string const& s) : _s(s) { }
private:
    string _s;
};

C++11 では、ムーブ セマンティクスがあるため、定数参照で渡すのではなく、s単純に値で渡してメンバー変数に移動できます。

struct A
{
    A(string s) : _s(move(s)) { }
private:
    string _s;
};

渡される値のコピーを常に生成することになるため、これは理にかなっています。

コメントでBenjamin Lindleyが正しく指摘しているように、これが受け入れられる場合は、参照によって引数を取る上記のコンストラクターのオーバーロードを記述できます。

struct A
{
    A(string const& s) : _s(s) { }    // 1 copy
    A(string&& s) : _s(move(s)) { }   // 1 move
private:
    string _s;
};

上記のバージョンでは、左辺値に対して 1 つのコピーのみを実行し、右辺値に対して 1 つの移動を実行できますが、値渡しのバージョンでは、常に追加の移動を 1 つ実行します。したがって、この解決策は、移動が引数の型の高価な操作である場合に適しています (これは の場合ではありませんがstring、他の型の場合には当てはまる可能性があります)。

ただし、関数が複数の引数を取る場合、これは面倒な場合があります。労力を軽減するために、ユニバーサル参照を取り、その引数を完全転送する単一の関数テンプレートを作成できます。StackOverflow に関するこの Q&Aは、主題に関連しています。

于 2013-02-28T15:18:36.200 に答える