6

C++ ドラフトには次のように記載されています。

12.8p31 コピー省略と呼ばれるこのコピー/移動操作の省略は、次の状況で許可されます (複数のコピーを排除するために組み合わせることができます)。

(...)

  • 参照 (12.2) にバインドされていない一時クラス オブジェクトが同じ 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?
}
4

1 に答える 1

3

コピーが省略されることは決してわかりません。コピーの省略は必須ではありません。

したがって、両方のケースが UB であるか、またはなしのいずれかです。StaticStuff:send渡すオブジェクトの処理によって異なります。y._xRefまたはへのポインター/参照を保持している場合、 が返さ*y._xPtrれた後にそのポインター/参照を逆参照するMakeX()と、実際に UB が発生します。元のオブジェクトxは、内部に自動ストレージ期間MakeX()とその有効期間を持つオブジェクトであったためです。が終了しました。

この UB の結果が「すべて正常に動作する」可能性があります。これは、コピーの省略が行われ、ポインター/参照が「外側のスタック フレーム」内のインスタンスを参照しているためです。ただし、これはまったくの偶然であり、まだ UB です。

于 2013-04-08T08:25:34.960 に答える