C ++ 11範囲ベースのループ:値で項目を取得するか、constへの参照


215

彼らは、2つの主要な方法を示唆している範囲基づいてループのいくつかの例読み出し1234

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

または

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

上手。

vecアイテムを変更する必要がない場合、IMO、例では2番目のバージョン(値による)の使用を提案しています。彼らがconst参照するものを提案しない理由(少なくとも直接的な提案は見つかりませんでした):

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

良くないですか?それがである間、それは各反復で冗長なコピーを避けませんconstか?

回答:


390

アイテムを変更したくない場合や、コピー作成したくない場合auto const &は、正しい選択です。

for (auto const &x : vec)

使用を勧める人はだれでもauto &間違っています。それらを無視してください。

ここに要約があります:

  • auto xコピーをいつ使用するかを選択します。
  • auto &x元のアイテムをいつ使用するかを選択し、変更する場合があります。
  • auto const &x元のアイテムを使用して、変更しない場合に選択します。

21
すばらしい答えをありがとう。const auto &x3番目の選択と同等であることも指摘する必要があると思います。
smg 2015

7
@mloskot:同等です。(そして、「しかし、それは同じ構文ですとはどういう意味ですか?構文は明らかに異なります。)
Nawaz

14
行方不明:auto&&不必要なコピーを作成したくない場合、それを変更するかどうかに関係なく、そのまま作業したい場合。
Yakk-Adam Nevraumont、

4
int / doubleのような基本的な型で作業している場合、参照の区別はコピーに適用されますか?

4
@racarate:全体の速度についてコメントすることはできません。最初にプロファイリングしないと、誰もコメントできないと思います。率直に言って、コードの明確さではなく、速度に基づいて選択することはしません。不変性が必要な場合はconst、確実に使用します。しかし、それはであるかどうかauto const &、またはauto const ほとんど違いがあります。auto const &一貫性を保つためだけに選択します。
Nawaz、2016

23

あなたが持っている場合std::vector<int>std::vector<double>、それを利用するだけで結構ですauto(値のコピーで)の代わりにconst auto&コピーするので、intまたはdouble安いです。

for (auto x : vec)
    ....

しかし、あなたが持っている場合はstd::vector<MyClass>、どこMyClassいくつかの非自明なコピー・セマンティクスを持っている(例えばstd::string、いくつかの複雑なカスタムクラスなど)は、私が使用してお勧めしたいconst auto&ディープコピーを避けるために

for (const auto & x : vec)
    ....

3

vecアイテムを変更する必要がない場合、例では最初のバージョンを使用することをお勧めします。

それから彼らは間違った提案をします。

なぜconstが参照するものを提案しないのか

彼らは間違った提案をするからです:-)あなたが言及することは正しいです。オブジェクトを観察するだけの場合は、コピーを作成する必要はなく、オブジェクトへの非const参照を持つ必要もありません。

編集:

あなたがリンクしているすべての参照には、int値の範囲またはその他の基本的なデータ型を反復する例が示されています。その場合、コピーintは高価ではないので、コピーを作成することは、観察することと基本的に同等です(より効率的ではないにしても)const &

ただし、これは、一般にユーザー定義型には当てはまりません。UDTはコピーにコストがかかる可能性があり、コピーを作成する理由がない場合(元のオブジェクトを変更せずに取得したオブジェクトを変更する場合など)は、を使用することをお勧めしますconst &


1

ここで反対になりauto const &、範囲ベースのforループの必要がないと言います。次の関数がばかげている(その目的ではなく、記述方法が間違っている)と思われる場合は、教えてください。

long long SafePop(std::vector<uint32_t>& v)
{
    auto const& cv = v;
    long long n = -1;
    if (!cv.empty())
    {
        n = cv.back();
        v.pop_back();
    }
    return n;
}

ここで、著者はvvを変更しないすべての操作に使用するためのconst参照を作成しました。これは愚かであると私は考えています。同じ引数auto const &をforループの範囲として変数として使用するだけでなく、auto &


3
@BenjaminLindley:だから私はあなたがconst_iteratorforループでも反対するだろうと推測できますか?繰り返し処理するときに、元のアイテムをコンテナから変更しないようにするにはどうすればよいですか?
Nawaz 2013年

2
@BenjaminLindley:コードがないとコードがコンパイルされないのはなぜconst_iteratorですか?推測してみましょうconst。イテレータを繰り返したコンテナはです。しかし、なぜそれconstが最初にあるのでしょうか?どこであなたがconst何を確実にするために使用していますか?
Nawaz 2013年

8
オブジェクトを作成するconst利点は、クラスでprivate/ を使用する利点に似ていprotectedます。それはそれ以上の間違いを避けます。
masoud 2013年

2
@BenjaminLindley:ああ、私はそれを見落としていた。この場合、実装もばかげています。ただし、その関数が変更vされなかった場合、実装は正常なIMOになります。そして、ループが反復するオブジェクトを変更しない場合、私はを参照するのが正しいようですconst。私はあなたの要点を理解しています。鉱山は、ループが関数とほぼ同じようにコード単位を表し、その単位内に値を変更する必要のある命令がないことです。したがって、メンバー関数のconst場合と同様に、ユニット全体をとして「タグ付け」できconstます。
Andy Prowl 2013年

1
だから、あなたconst &は範囲ベースはばかげていると思います、あなたはcv -qualificationで何かばかげたことをした架空のプログラマーの無関係な架空の例を書いたからですか?... OK
underscore_d
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.