2016-09-22 11 views
2

すべてのコンストラクタが定義されたシンプルな構造体があります。 int変数を持ち、各コンストラクタと代入演算子は、* thisのアドレス、現在のint値、新しいint値を出力します。 割り当て演算子とコンストラクタを移動してコピーすると、渡された値のアドレスも出力されます。値渡しファンクションの追加移動コンストラクタ

#include <iostream> 

struct X 
{ 
    int val; 
    void out(const std::string& s, int nv, const X* from = nullptr) 
    { 
     std::cout<<this<<"->"<<s<<": "<<val<<" ("<<nv<<")"; 
     if (from) 
      std::cout<<", from: ["<<from<<"]"; 
     std::cout<<"\n"; 
    } 

    X(){out("simple ctor X()",0); val = 0;} 
    X(int v){out("int ctor X(int)", v);val = v; } 
    X(const X& x){out("copy ctor X(X&)", x.val, &x);val = x.val; }; 
    X&operator = (const X& x){out("copy X::operator=()", x.val, &x); val = x.val; return *this;} 
    ~X(){out("dtor ~X", 0);} 
    X&operator = (X&& x){out("move X::operator(&&)", x.val, &x); val = x.val; return *this;} 
    X(X&& x){out("move ctor X(&&x)", x.val, &x);val = x.val;} 
}; 

X copy(X a){return a;} 

int main(int argc, const char * argv[]) { 
    X loc{4}; 
    X loc2; 
    std::cout<<"before copy\n"; 
    loc2 = copy(loc); 
    std::cout<<"copy finish\n"; 
} 

出力:

0xffdf7278->int ctor X(int): 134523184 (4) 
0xffdf727c->simple ctor X(): 134514433 (0) 
before copy 
0xffdf7280->copy ctor X(X&): 1433459488 (4), from: [0xffdf7278] 
0xffdf7284->move ctor X(&&x): 1433437824 (4), from: [0xffdf7280] 
0xffdf727c->move X::operator(&&): 0 (4), from: [0xffdf7284] 
0xffdf7284->dtor ~X: 4 (0) 
0xffdf7280->dtor ~X: 4 (0) 
copy finish 
0xffdf727c->dtor ~X: 4 (0) 
0xffdf7278->dtor ~X: 4 (0) 

は(この例では)アドレス0xffdf7284で追加のオブジェクトを作成する目的は何ですか?

答えて

2

copy elision rules from cppreference.comを見ると、コピー/移動コンストラクタとデストラクタが観測可能なサイドバイサイドオブジェクトを持っていても、コンパイラがクラスオブジェクトのコピーコンストラクタとムーブコンストラクタを省略する必要があることがわかります。エフェクト(印刷物のためにあなたがするもの)。最初はこのケースとは明らかに無関係です。 2つ目は

return文のオペランドがprvalueであり、関数の戻り値の型がそのprvalueの型と同じ場合に呼び出されます。例では

T f() { return T{}; } 
T x = f(); 

これは、より関連性のようだが、しかし、あなたの場合には、return文のオペランドがprvalueではないことに注意してください。この場合、必須のエリミケーションは適用されません。 loc2 = copy(loc);を呼び出すときに、次のように

一連の手順、次のとおりです。

  • alocからコピー構築です。
  • 関数の戻り値はaからmove-constructです。
  • loc2は戻り値から移動割り当てされます。

論理的には、人がコードを見て、より少ない操作が行われる必要があることを推測することができ(copyを見ると、特に、それは、論理的に、locからloc2への割り当てが十分であることは明らかです)が、コンパイラは、コードの目的が副作用(印刷物)を生成しないことを知らず、ここで規則を破っていません。

+0

それで、適切な値を作成するために呼び出されますか? –

+0

@ Guy-WithA-gum正確にはありません。それは価値がなく、すべてのメソッドに副作用があるので、それを移動してからデストラクタを呼び出します。これは、単に価値を全く伴わない。 –

+0

なぜ "a"が返されないのですか?なぜ、それは構築値から移動する必要がありますか –

関連する問題