2016-07-23 2 views
-1

はvs13に次のコードを書きました。 myvectorはまだ彼の "Hello World"を最後に持っていました。このような通常のC++ 98の繰り返し使用 :はSTD ::動きが動かなかったのはなぜ

std::vector<std::string> myvector(1000); 
std::fill(myvector.begin(), myvector.end(), "Hello World"); 
std::vector<std::string> pushto; 
for (auto s = myvector.begin(); s != myvector.end();s++) 
    pushto.push_back(std::move(*s)); 

は実際に働いていた、との動きが呼び出されました。 myvector文字列が空でした。 最初のより現代的な表記がなぜ機能しないのですか?

+4

は、最初の例では、実際にコンパイルしていますか?私は 'std :: move(* s)'に '*'があるべきではないと思います。 – aschepler

+0

誰も移動がオリジナルを消去するはずはないと言ったことに注意してください。移動後、オリジナルは*有効であるが不特定の*状態にある。 '&'を置いても、元のオブジェクトが新しいオブジェクトと同じ値(つまり、変更前と同じ値)を持つことは完全に有効です(そして、時には必要な場合もあります)。 – lorro

答えて

5

最初の例では、for (auto s: myvector)を使用しています。この場合、sは現在の反復の値のコピーです。あなたが望むものを達成するために、あなたは参照によってそれをするべきです - for (auto& s: myvector)

std::moveの後に文字列が空になることは保証されていないことに注意してください。この呼び出しは、引数を右辺参照(&&)にキャストします。 rvalue referece引数のオーバーロードを持つ他の関数(std::vector::push_backなど) argnetetリソースを解放する可能性があります。

+2

..それでも、古い文字列を空にすることは保証されません。 – lorro

+0

確かに、これは 'std :: move'を使う正しい方法です(2番目の例では空になっているため、OPのコンパイラで空になるでしょう)。 – Xiobiq

+0

正しい方法:間違いなく私はあなたに同意します。例外を除いて、それはコンパイラのクラス*と*の実装の詳細です(どちらもどちらでもありません)。 – lorro

3

@Polikdirによると、コピーは(auto s: myvector)で作成したコピーに由来しています。一つの方法は、&&(転送参照)または&(正常参照)と、レンジのループを使用することである。よく知られていない

for (auto & val : myvector) 
    pushto.push_back(std::move(val)); 

が、コンテナ間でオブジェクトを移動させるための専用のアルゴリズムがあります。実際にはstd::moveとも呼ばれています。

std::move(s.begin(), s.end(), std::back_inserter(pushto)); 

編集:

Q:のstd ::ので、動きはちょうどそれが本当に必要とされている右辺値参照にキャスト?この場合、std :: moveは冗長ではありませんか?いいえ、変数(valなど)はr値参照にできないためです。そのため、普遍的な参照でstd::forward<T>に電話する必要があります。

も注意してください。What does `auto && e` do in range-based for-loops?

+0

'std :: move'はrvalue参照にキャストするだけで本当に必要ですか?この場合の 'std :: move'は冗長ではありませんか? – Xiobiq

+1

3パラム 'move'、良いヒント。 – lorro

+0

ありがとう、非常に役立つソリューション – orenshochat

関連する問題