2013-02-06 4 views
18

私はチャットで、次の例を示された。ref-to-const一時的な生涯延長は「一度しか動作しません」という標準的な言い回しはありますか?

#include <iostream> 
struct foo { ~foo() { std::cout << "destroying!\n"; } }; 
const foo& func(const foo& a, const foo&) { return a; } 

int main() 
{ 
    foo x; 
    const foo& y = func(foo(), x); 
    std::cout << "main\n"; 
} 

Output

destroying! 
main 
destroying! 

foo、一時の寿命はそれを取得にもかかわらず、mainの全体に拡張されていないことを証明しているように見えますその範囲内のref-to-constにバインドされています。

おそらく、その後、生涯延長は「1回だけ」機能します。つまり、funcの引数が初期化されたときに適用されますが、連続するバインディングを介して渡されることはありません。

私の解釈は正しいですか?もしそうなら(そして個々のパラグラフが直接適用可能な場合)、この振る舞いを定義する標準的な言い回しは何ですか?

+0

'func'の第2引数は何ですか?あなたがそれを残すと(そして 'x')何が起こるでしょうか? –

+0

@ KonradRudolph:これは、テキスト "main"の出力に対する破壊命令を示すためのものです。 –

答えて

7

これは、2つの発行レポートhttp://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299およびhttp://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1568の件名です。

私がレポーターである前回の問題報告は、一時的なオブジェクトに参照がバインドされているが、生涯にわたるものではないこれらすべてのケースをカバーすることを意図していました。問題の本文には、評価されたものの存続期間が長くなっているかどうかを実際に判断する一時的な表現と混同されているPR値のみが記載されています。しかし、左辺値とx値も同様に標準と混同されます。 static_castの文脈でそれが起こる例は、issue番号#1568(「一時変数」の使用がさらに問題を混乱させる)です。実際

、この:

関数呼び出し(5.2参照パラメータを一時的にバインドされました。2)は、呼び出しを含む完全表現が完了するまで続きます。

同じ段落の他の規則と矛盾します。テンポラリはにバインドされているため、は、関数呼び出しの参照パラメータとローカル自動参照変数の両方です。

+0

ええ、あなたとJamesは、 "except"という単語が一度に1つのシナリオにしか適用されていないので、 "except"という単語が段落のルールを曖昧にしないと私に確信しています。より矛盾するシナリオ –

8

あなたはほぼ正しいです。この振る舞いは実際に関数呼び出しから来るもので、「一度しか動作しません」というルールのためではありません。

適切なルールを太字で強調してここでは、全体の寿命延長「機能」のための言葉遣いです:

[C++11: 12.2/5]:[..]は一時的な参照がバインドされているか、一時的なものであるに参照がバインドされているサブオブジェクトの完全なオブジェクトは以外参照の寿命持続:

  • [..]
  • 関数呼び出し(5.2.2)の参照パラメータへの一時的なバインドは、呼び出しを含む完全式が完了するまで続きます。
  • [..]
+0

しかし、この場合、一時的な値はconst参照 'y'にも束縛されます。だから、その参照はその寿命を制御しますか? –

+1

@JamesKanze:「例外」リストが優先されています。 –

+0

私はあなたが何を意味するのか見ていますが、私はまだそれがあいまいだと思っています。それが意図ならば、それを指定する少しの厄介な方法です。まず、リファレンスが一時的かどうかに基づいて一意に基づいて延長された生涯を保証します。次に間接参照につながる可能性のあるすべてのケースを排除します。 。 –

3

ここに適用されるルールは常識です。標準は であり、実際にはこれを保証しています。しかし、それを実装する実際の方法はありません。

+0

どういう意味ですか?制限を実装する現実的な方法、または現在発生していない生涯延長を実装する方法はありませんか? –

+0

@LightnessRacesinOrbit仮のライフタイムを、それがバインドされている最後の参照まで拡張するような強制的な方法はありません。 –

+0

私は@Jamesが私の答えに要約していることを話していると思います。 –

1

おそらく私は少し遅いですが、私にはこの質問の解決が他の回答を読んでいることは明らかになりませんでした。したがって、私はコードを修正し、他の人のためにまとめたいと思っていました。答えは、の定義されていない動作yにアクセスすれば得られます!

を実行し、このコード:

struct foo { 
    int id; 
    foo(int id) : id(id) { std::cout << "ctor " << id << std::endl; }; 
    ~foo() { std::cout << "dtor " << id << std::endl; } 
}; 
const foo& func(const foo& a, const foo&) { return a; } 

int main(int argc, char** argv) { 
    foo x(1); 
    const foo& y = func(foo(2), x); 
    std::cout << "main " << y.id << std::endl; 
    return 0; 
} 

私のための出力は次のとおりです。

ctor 1 
ctor 2 
dtor 2 
main 2 
dtor 1 

しかし、ラインmain 2未定義の動作です。

関連する問題