2

以下のコードの結果に異議を唱えているわけではありません。const 左辺値参照と右辺値参照の両方が、関数から返される一時値の有効期間を延長すると仮定するのが正しいと思うからです。私が驚いたのは、標準の次の段落です。これは、反対のことを言っているようです。

12.2p5 (強調鉱山):

2 番目のコンテキストは、参照がテンポラリにバインドされる場合です。参照がバインドされている一時オブジェクト、または参照がバインドされているサブオブジェクトの完全なオブジェクトである一時オブジェクトは、次を除いて、参照の存続期間中持続します。

  • ...
  • ...
  • 関数 return ステートメント (6.6.3) の戻り値に一時的にバインドされているものの有効期間は延長されません。一時的なものは、return ステートメントの完全な式の最後で破棄されます。

コード例:

#include <iostream>

struct A{ A() : i(2) {} int i;};

A f() { A a; return a; }

int main()
{
    A&& a1 = f();
    std::cout << a1.i << '\n';
    const A& a2 = f();
    std::cout << a2.i << '\n';
}
4

2 に答える 2

5

あなたが言及した引用は、関数から参照を返し、その参照を一時的にバインドするためのものです。

const T& f() { return T(); };

returnステートメントではなく、呼び出し側で一時を参照にバインドしているため、コードではそうではありません。コメントでは、コードを次のように変更すると次のようになります。

T f() { return T(); }
T&& r = f();

寿命はまだ延長されていますが、それは間違っています。return一時的なものは、返された値にコピーされるステートメントの期間中存続します。コピーが完了すると、一時的な有効期間が終了します。f()呼び出し側では、存続期間が延長される別の一時 ( の結果) があります。

しかし、テンポラリーの寿命が延びていることは間違いありません。クラス A のデストラクタを任意のメッセージで定義すると、それは main() の最後に出力されますか、それともありますか?

その発言も間違っています。戻り値の最適化 (RVO) の効果が見られます。T()関数内の一時オブジェクトと戻り値用の一時オブジェクトを作成する代わりに、コンパイラは同じ場所に 2 つのオブジェクトを作成しています。プログラムの出力にはおそらく 1 つのオブジェクトが表示されますが、理論的には 2 つのオブジェクトがあります。

-fno-elide-constructors を指定して g++ を使用すると、両方の一時オブジェクトが表示されるはずです。一方が拡張され、もう一方が拡張されません。

または、参照を返すこともできます。

const A& f() { return A(); }
const A& r = f();

r範囲外になる前に一時的に終了する方法を示す必要があります。


これは基本的に、

$ g++ --バージョン | 頭-1

g++ (GCC) 4.3.2

$ 猫 x.cpp

#include <iostream>

struct X {
    X() { std::cout << "X\n"; }
    ~X() { std::cout << "~X\n"; }
};

X f() { return X(); }

int main() {
    const X& x = f();
    std::cout << "still in main()\n";
}

$ g++ -o t1 x.cpp && ./t1

X
still in main()
~X

$ g++ -fno-elide-constructors -o t2 x.cpp && ./t2

X
~X
still in main()
~X

$ clang++ -バージョン | 頭-1

$ clang バージョン 3.2 (タグ/RELEASE_32/final)

$ clang++ -fno-elide-constructors -o t3 x.cpp && ./t3

X
~X
still in main()
~X

$猫y.cpp

#include <iostream>

struct X {
    X() { std::cout << "X\n"; }
    ~X() { std::cout << "~X\n"; }
};

const X& f() { return X(); }

int main() {
    const X& x = f();
    std::cout << "still in main()\n";
}

$ g++ -fno-elide-constructors -o t4 y.cpp && ./t4

X
~X
still in main()
于 2013-06-27T22:03:15.503 に答える