2017-01-29 16 views
0

免責事項:私はC++を初めて使用しています。std :: unordered_set戻り値の型vs値

私はこのようなコードブロックを持っている:

using BucketType = std::unordered_set<Bucket, BucketHash, BucketEqual>; 

    const BucketType& Range::buckets(int64_t value) { 
    BucketType buckets; 
    ... 
    return std::move(buckets); 
    } 

呼び出し側がこのようにこのコードを呼び出します。私のようなバケットの参照を返すとき

Range range; 
    auto buckets = range.buckets(11); 

問題上記のコードでは、buckets.size()140732261909672ですが、私は実際のロジックに2つのバケットしか追加していません。参照の代わりに値を返すようにコードを変更すると、正常に動作します。

このコードで何が間違っている可能性がありますか?

+0

&から削除してくださいバケットの戻り値の型。 –

+2

本当に最善であるまれなケースでない限り、値を返すために 'std :: move'を使用しないでください。できるだけ戻り値を移動させるだけでなく、 'std :: move'を使うことで、(N)RVOのさらに良い結果を実際に防ぐことができます。現在、これは一般に参照によるのではなく、バイナリの戻り値に適用されます。私はあなたの望む動作がこの戻り値に対して何であるか分かりません。 – chris

+1

短いバージョン:動作と使用方法が分からない限り、['std :: move'](http://en.cppreference.com/w/cpp/utility/move)は使用しないでください。 – WhozCraig

答えて

1

あなたbuckets関数を考えます:ここで

const BucketType& Range::buckets(int64_t value) { 
    BucketType buckets; 
    ... 
    return std::move(buckets); 
} 

あなたは一時的なこのにバインドconst参照を返し、その後、関数の戻り値の場所に移動それをタイプBucketTypeのローカルオブジェクトを作成しますオブジェクトです。間違いなく、未定義の動作につながります。

、このような関数を書くための正しい方法は、コードを簡素化することで、const BucketType&std::move(buckets)を取り除く:

BucketType Range::buckets(int64_t value) { 
    BucketType buckets; 
    ... 
    return buckets; 
} 

bucketsは(戻り値の最適化と命名)NRVOのために利用可能になります。これは、すべての現代のコンパイラはここコピーの省略を行うと、彼らはbuckets機能で初期化されている(関数の戻り値の場所に一時オブジェクトを作成せずに)直接BucketTypeオブジェクトを構築することを意味します

auto buckets = range.buckets(11); // No unnecessary copies here 
+0

'const'を返すオブジェクトをドロップした場合、何らかの理由でコピーを省略できない場合(' ... 'が何を意味するか分からずにエリジョンを保証することができません)、返却用のカムを移動させます。 – juanchopanza

+0

@juanchopanzaはい、間違いなく! –