2016-08-13 6 views
34
#include<iostream> 
using namespace std; 

struct B{}; 

struct A 
{ 
    A(const B &) 
    { 
     cout<<"A(const B &)"<<endl; 
    } 
    A(B &&) 
    { 
     cout<<"A(B &&)"<<endl; 
    } 
}; 

A get() 
{ 
    B b; 
    return b; 
} 

int main() 
{ 
    get(); 
} 

私はVC++ 14.2とGCC 5.4.0を使用してコードをテストし、それらの両方が出力:この場合、r値参照コンストラクタが呼び出されるのはなぜですか?

A(B &&) 

なぜ

A(const B &) 

出力はありますか?

このコードは、copy elisionと関連がありますか? (ただし、AとBは異なるタイプなので、copy elisionはここでは働かないはずです)

+1

これは実際には非常に興味深い質問です。私は12.8/32の文言がやや不明であることを知っています:規則が適用されるためには、戻り式の型が関数の戻り値の型と同じでなければならないかどうかは不明です。私はあなたがそれを読み取ることができると思う*任意の*自動保存されたオブジェクトは、rvalueによって指定されたと見なされます。異なるコンパイラ[これについて別々に考える](http://melpon.org/wandbox/permlink/meIAgmvSOVq435vy)。 –

+0

[CWG1579](http://wg21.link/cwg1579)がここに該当します。 –

+0

@KerrekSB(31.1)によると、式が の名前である場合(関数パラメータまたはハンドラ(15.3)の例外宣言によって導入された変数を除く)の不揮発性自動オブジェクト(cv-qualificationを無視して)関数の戻り値の型として ''同じ型 'は 'return型'とまったく同じでなければならないと思います。つまり、 'A'オブジェクトを返すと' copy elision'が動作します。しかし、 'B'から' A'への暗黙的変換は ''コピーエリジョン ''の前に行われ、 ''コピーエリッション ''は ''暗黙の変換 ''に影響しないはずです。 – Caesar

答えて

29

C++ 14の公開前のレビューに応じて、戻り値としての規則が変更されました。

又はreturn文の式が(おそらく括弧)ID発現ある名:変化がプロセスの後期に添加し、CWG Issue 1579によって捕捉され、それは、文言で12.8/32を改訂します自動記憶域期間を持つオブジェクトは、(オーバーロードの解決に失敗した場合に再試行)。これは、それが最初の右辺値であるかのように任意のローカル変数を返すことは、今、その変数で指定されたオブジェクトを考慮することを意味し、本体

で宣言されました。

CWGの問題は言語の欠陥として受け入れられたため、コンパイラは「C++ 11モード」でもこの新しいルールを実装できます。欠点のポイントは、「それは常にそのように働くことを意味していた」ということです。これは厳密にはC++ 11とC++ 14の間の変更ではなく、むしろC++ 11の意味が変更されています

+0

この声明はn4594§12.832にあります。私は 'コピーelision'が満たされたときにのみ動作すると思っていました! – Caesar

+0

@Caesar:はい、それは以前のようでした。しかし、リンクされたコアの問題は、 "それがもっと一般的に働くといいだろう"ということでした。そして、それを変える国家のコメントがあったので変更されました。リンクされた問題には、あなたと非常によく似た動機づけの例が含まれています。 –

+0

@Caesarええ、私は毎回これを読んでいる間違いを犯します。それは非常に複雑な文章です。しかし、このように考えてみてください。自動ストレージ変数を名前で返す場合は、移動するのは間違いないので、自動的にその変数を使用してみてはどうでしょうか? – Barry

5

コピーelisionはAに関連しており、get()スタックフレームでは作成されていません。 返されたb(これは "戻りのために死に至りました"から一時的です:これはC++ 14以降です)、メインスタックフレームにコピーされたAを構築するために使用されています。

一時オブジェクトは、あなたが観察したr値参照をバインドします。

+0

ISO C++標準(現在、n4594)のステートメントはどこにありますか? – Caesar

+0

私はそれについてここで読んでいます:http://en.cppreference.com/w/cpp/language/return –

+1

まあ、 'copy elision'を実行する前に暗黙の変換があります。 – Caesar

関連する問題