2013-04-08 8 views
6

C++ドラフト状態:コピーの省略、一時バウンド・バイ・REFオブジェクト

12.8p31コピーの省略と呼ばれるコピー/移動操作のこのエリジオンは、に組み合わせることができる(以下の状況において許容されます)複数のコピーを排除:を参照(12.2)にバインドされていないことを、一時的なクラスのオブジェクトは/を移動、コピーされるだろう

(...)

  • 0は、同じCV-非修飾型のクラスオブジェクトを、コピー/移動操作は、換言すれば

を移動/省略コピーの標的に直接、一時的なオブジェクトを構築 によって省略することができる。

X MakeX() { 
    return X(); // Copy elided 
} 

X MakeX() { 
    const X& x = X(); // Copy not elided 
    return x; 
} 

参照ため、このような制限の理由は何ですか?

一時的なものと参照番号との違い(IMHO)が表示されないことを示すために、以下の例の妥当性には焦点を当てないでください。

参照の導入によって、他のピアが同じオブジェクトのエイリアスを許可する一方、MakeX()の呼び出し元は、それが安全で清潔であると予想します。

class Y { 
public: 
    Y(const X& x) : _xRef(x) {} 
private: 
    const X& _xRef; 
}; 

X MakeX() { 
    const X& x = X(); 
    Y y{x}; 
    StaticStuff::send(y); 
    return x; // Oops, I promised to return a clean, 
       // new object, but in fact it might be silently 
       // changed by someone else. 
} 

しかし、このような場合(おそらくそれはUBだ;)に関する):

class Y { 
public: 
    Y(X* x) : _xPtr(x) {} 
private: 
    X* _xRef; 
}; 

X MakeX() { 
    X x; 
    Y y{&x}; // I'm referencing a local object but I know it will be 
      // copy elided so present in the outer stack frame. 
    StaticStuff::send(y); 
    return x; // Copy elided? 
} 
+2

'StaticStuff :: send(y);'は実際に 'x'を間接的に変更する可能性を導入していません=>' MakeX'の終わりの後に 'x'への参照を使う未定義の動作です。 –

+1

'おっと、私は清潔で新しい物を返すことを約束しましたが、実際には他の誰かによって静かに変更されるかもしれません。 'x'は' const X& 'ですので変更できません。 –

+0

'MakeX'の2番目のバージョンはおそらくコピーコンストラクタを呼び出して' const X& 'を普通の' X'にします。 – didierc

答えて

3

あなたは決してはコピーが省略されることを知っています。コピーelionは決して必須ではありません。

したがって、どちらのケースもUBであるか、またはどちらもありません。 y._xRefまたは*y._xPtrへのポインタ/参照を保持している場合は、MakeX()が返された後でポインタ/参照を逆参照すると、元のオブジェクトとして実際にUBが発生します。xは自動ストレージ付きのものでした期間はMakeX()であり、その有効期間は終了しました。

コピーellisionが実行され、ポインタ/参照が「外部スタックフレーム」内のインスタンスを参照しているため、このUBの結果は「すべて正常です」となる可能性があります。しかし、これは純粋な偶然であり、まだUBです。

+0

確かに、「Elision(...)は許可されています」と言われているので、私は何も期待できません。そして、そういう2つのケースで私はUBの土地を歩いています。私が言いたいのは、一時的なものではあるがconst ref(一時的なものを保持する唯一の方法)が許可されていない特定の理由はわかりません。 –

+0

私はこれが少なくともC++ 11ではなく、まったく正しいとは思いません。 'X'が移動可能ではあるがコピーコンストラクタブルではない場合はどうでしょうか?その後、OPの最初の例はまだコンパイルされ、コンパイラは 'move elision'を強制されますか? 詳しくはhttp://stackoverflow.com/questions/18609968/is-default-constructor-elision-assignment-elision-possible-in-principleを参照してください。 – eold

+0

@leden私はまったくフォローしません。 **コピー/移動のエリシジョンを強制的に** ** **発生させる方法はありません。それらは常に*オプションです。 – Angew

関連する問題