2017-06-06 7 views
1

私は移動機能(例えばhttp://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html)についていくつかの記事を読んでいます。だから私は、次のコードを試してみました:C++ - NRVO and move

#include <vector> 
#include <cassert> 
#include <functional> 
#include <algorithm> 
#include <iostream> 
using namespace std; 

vector<double> operator+(const vector<double>& a, const vector<double>& b){ 
    assert(a.size()==b.size()); 
    vector<double> result(a.size(),0); 
    transform (a.begin(), a.end(), b.begin(), result.begin(), std::plus<double>()); 
    cout<<&result<<endl; 
    return result; 
} 

int main(int argc, char const *argv[]) { 
    vector<double> a,b; 
    for (int i=0;i<10;i++){ 
    a.push_back(i); 
    b.push_back(1); 
    } 
    std::vector<double> c=a+b; 
    cout<<&c<<endl; 
    return 0; 
} 

私は移動演算子がvectorのために実装されているので、ローカル変数resultcに同じアドレスを取得するために期待していました。そして私は正確にそれを得ましたが、フラグがある場合とない場合-std=c++11。それがNRVO(c++11 Return value optimization or move?)について学んだので、私はフラグ-fno-elide-constructorsでそれを無効にしました、そして今、アドレスは-std=c++11であっても異なっています。私のコードに問題はありますか、または移動オペレータについて間違ったことを理解しましたか?

私が理解したところでは、値を返すことは、移動オペレータが(C++11 rvalues and move semantics confusion (return statement))を開始するのに十分でなければなりません。

PS:GCC 6.3.0_1とApple LLVMバージョン8.1.0を試しました。

EDIT

としては、私は(下記参照)result.data()の代わり&resultをチェックしているはず、と指摘しました。しかし、その場合は、std=c++11-fno-elide-constructorsがなくても、私はいつも同じアドレスを見つけました。受け入れられた回答とそのコメントセクションを参照してください。

答えて

2

移動を最適化したコピーと考えてください。まだコピーされているので、それはまだ別のベクトルですが、基礎となるデータをあるベクトルから別のベクトルに「移動」させました。一方、

cout<<result.data()<<endl; 

cout<<c.data()<<endl; 

コピーの省略が完全にコピーを排除します。あなたはそのデータのアドレスを比較して見ることができます。

+1

すぐにお返事ありがとうございます。私は 'data'で試してみました。しかし、私は '-fno-elide-constructors'と' -std = C++ 11 'を使わないで同じアドレスを取得します。奇妙なんじゃない?どのようにして、コンパイラは、コピー・エリートと移動演算子を使用せずに最適化できますか? –

+0

@PierreMarchandあなたの質問では、 '-fno-elide-constructors'はいつも別のアドレスを与えたと言いました(私が期待しているもの) –

+0

@MM私は彼らが' .data() 'のアドレスを参照していると思います –

3

移動コンストラクタは、古いオブジェクトのリソースを盗み出して新しいオブジェクトを構築します。それは一時的なものを全くマージしません。もし構造が省略されなければ、あなたはまだ2つのオブジェクトを持っています。