2016-06-17 8 views
0

このコードはなぜ機能しますか?毎回60を出力します。まず、​​3210は、関数が名前のない構造ではなく、既存の変数への参照を返すことを示します。第二に、関数が返ってきたときに一時的に死んではいけません。私は最新のGCCバージョンがOSX上にあるものを使用しています...誰かが私にこの理由を説明してもらえますか?rvalueへのconst左辺参照を一時的に返しますか?なぜこれは機能しますか?

#include <iostream> 

using namespace std; 

struct thingy { 
    double things; 
    double moreThings; 
    double evenMoreThings; 
}; 

const thingy& getThingy() { 
    return {60, 60, 60}; 
} 

int main() { 
    cout << getThingy().evenMoreThings << endl; 
} 

これが機能するのであれば、どうしてですか?

const thingy& getThingy() { 
    thingy t{60, 60, 60}; 
    return t; 
} 
+2

これらはどちらも未定義の動作なので、動作するように見えるものもあります。 – GManNickG

+0

@GManNickG最初の例は毎回動作するようです。私はそれをしないと壊れているwhileループに置いても、複数の試行でうまくいきます...あなたが受け入れられた答えを読んだら、私はそれが起こっていると思います。コンパイラの愚かさ、これは技術的に起こってはならないことを意味する...? – Naerion

+1

毎回動作するように見えるのは、未定義の動作に対しては完全に有効な動作です。それはあなたの製品をデモする日の作業を停止します。 – GManNickG

答えて

1

ここではコンパイラが戻り値の最適化を実行しています。

https://en.wikipedia.org/wiki/Return_value_optimization

コンパイラは、リターンで構築された値を取ることができ、さらには、それをコピーする必要はありません。しかし、関数内で構造体を構築する例では、実際にはローカル変数であるため、関数の終わりにスコープから外れて参照が無効になります。

+0

私は、なぜ、これがうまくいかないのか聞いてもらえますか? 'return thingy(t);'私はこれらのことについてよく知っているわけではありませんが、これは一時的に作成し、 'return {60,60,60};のようにconst参照にバインドすると信じています。 – Naerion

+2

@Naerion:これらのどれも "仕事"はありません。 RVOはこの特定のクォークを説明するかもしれませんが、あなたは存在しないものへの参照を返すことはできません。未定義の動作は、動作しているように見えることがあります。 – GManNickG

2

どちらのオプションも、が必要です。は、C++標準で動作する必要がありません。したがって、いずれかの特定の状況で必ず動作すると見なされるべきではありません。

コンパイラの仕様によって、値を直接返す場所で最初のオプションが動作しています。

理想的には、互換性を保証するために値(thingy getThingy();)で戻すことをお勧めします。あなたの時間の価値のあるコンパイラは、これに戻り値の最適化を適用し、コピーコンストラクタ呼び出しの必要性を防ぎ、依然として必要な効率を可能にします。

+0

ありがとうございます。これは、RVOが発生しない状況を除いて、パフォーマンス上の問題がないことを意味しますか? – Naerion

+1

RVOは、ありがたいことに、すべての主要なコンパイラのよく実装された機能です。私はそれを当然のように受け止めている傾向があり、コピーコンストラクタにブレークポイントを置くことによって、実際にそれが有効になっているかどうかを実際に確認したい場合に、実際のデバッグを行います。 – Mitch

-1

rvalueとlvalueの参照を混同しないでください。 最良の選択肢は、コピーで返すことです。

ローカル変数のlavalue rerenseを返すと常に問題が発生します。

関連する問題