2016-09-08 5 views
1

を作る私の状況です:私はconst参照メンバ変数を持つクラスを持っているC++ 11でクラス基準部材の初期化は、ここで悪いコピー

  • 私はそのメンバ変数をconst参照から初期化しようとしています。

私の問題は、メンバ変数がクラス内で初期化されると、問題のオブジェクトの一時的なコピーが作成され、一時的なアドレスが参照に使用されるということです。メンバ変数がコンストラクタ初期化子リストで初期化されると、コピーは作成されません。どちらの方法でも、プログラムは、g ++ 4.8.3でC++ 11またはC++ 1yのいずれかのフラグを使用して警告なしで正常にコンパイルされます。

以下は、最小限のプログラムと出力です。私はちょうどそれがなぜ起こるか(またはそれがバグであるかどうか)知っているので、このよりよいルールを理解したいと思うでしょう。

#include <iostream> 
using namespace std; 
struct A 
{ 
    A() 
    { 
     cout << "creating an A at " << this << endl; 
    } 

    A(const A & a) 
    { 
     cout << "copying an A from instance at " << & a << " to instance at " << this << endl; 
    } 
}; 

A g_aardvark; 

const A & GetAardvark() 
{ 
    cout << "returning an A at " << & g_aardvark << endl; 
    return g_aardvark; 
} 

struct B 
{ 
    B() 
     : m_a1(GetAardvark()) 
     , m_a2(g_aardvark) 
    { } 
    const A & m_a1; 
    const A & m_a2; 
    const A & m_a3{ GetAardvark() }; 
    const A & m_a4{ g_aardvark }; 
}; 

int main() 
{ 
    B butter; 
    cout << "B has m_a1 at " << & butter.m_a1 << endl; 
    cout << "B has m_a2 at " << & butter.m_a2 << endl; 
    cout << "B has m_a3 at " << & butter.m_a3 << endl; 
    cout << "B has m_a4 at " << & butter.m_a4 << endl; 
    return 0; 
} 

サンプル出力:

creating an A at 0x601494 
returning an A at 0x601494 
returning an A at 0x601494 
copying an A from instance at 0x601494 to instance at 0x7fffc595f87f 
copying an A from instance at 0x601494 to instance at 0x7fffc595f87e 
B has m_a1 at 0x601494 
B has m_a2 at 0x601494 
B has m_a3 at 0x7fffc595f87f 
B has m_a4 at 0x7fffc595f87e 
+0

メモリが役立つ場合、これはgccのリスト初期化のバグで、4.9で修正されています。はるかに単純なコードで再現できるはずです。 'int main(){A a; const&b {a}; } ' –

+0

どのコンパイラのバージョンを使用していますか?このコードにはコピーはありません:http://coliru.stacked-crooked.com/a/f30df5ef62b45420 –

答えて

2

前述これは悪名高いDR 1288の場合です。

const A & m_a4{ g_aardvark }; 

実際g_aardvarkから一時的に作成し、それに結合するであろう:不注意コードがいることを指定し公表C++ 11標準に欠陥がありました。これは当然のことではありませんが、g ++ 4.8は出版されたテキストに続きます。基準がDR 1288によって修復され、参照が直接結合するようにした。

Clangは常に賢明な動作を実装しましたが、g ++は4.9チェーンまで更新しませんでした。

See here標準参照とより簡単なテストケースで説明します。

関連する問題