2012-02-04 15 views
20

ながら、なぜ私が間違った答えを取得します:C++のコンストラクタ:ごみconst参照の初期化このコードで何が間違っている

class X 
{ 
private: 
     const int a; 
     const int& b; 
public: 
     X(): a(10) , b(20) 
     { 
     //  std::cout << "constructor : a " << a << std::endl; 
     //  std::cout << "constructor : b " << b << std::endl; 
     } 

     void display() 
     { 
      std::cout << "display():a:" << a << std::endl; 
      std::cout << "display():b:" << b << std::endl; 

     } 
}; 


int 
main(void) 
{ 
     X x; 
     x.display(); 
return 0; 
} 

を上記のコードは

display():a:10 
display():b:1104441332 

として私に結果が得られます。しかし私は、デフォルトのコンストラクタ内のコメント行を削除する場合、それは私に適切な結果を与える

constructor : a 10 
constructor : b 20 
display():a:10 
display():b:20 

お手数ですが、

答えて

24

への参照として、bを初期化しています。

20が作成され、コンストラクタのスコープに対してのみ存在します。

このコードの動作は非常に面白いです。私のマシンでは、投稿したものとは異なる値が得られますが、基本的な動作はまだ非決定的です。

参照ポイントが範囲外になると、代わりにガベージメモリの参照が開始され、予測できない動作が発生するためです。

Does a const reference prolong the life of a temporary?を参照。 C++標準の関連セクションへの答えhttps://stackoverflow.com/a/2784304/383402のリンクは、具体的に以下のテキスト:

​​

あなたは常に、コンストラクタ内の印刷で正しい値を取得していない、と稀に理由はここにあります後に(時には多分しかし!) 。コンストラクタが終了すると、リファレンスダングルとすべてのベットがオフになります。

+0

あなたの答えに感謝します。その結果を説明します。しかし、私はbを初期化する方法を知っているかもしれませんか? –

+1

@VivekBasappa:あなたが意図したように、変数を参照してください。あるいは、単に 'a'のような値にしてください。 –

+1

@VivekBasappaそれは 'int'なので、おそらくそれが何とか参照になりたくないでしょう。 'int'をコピーすることは費用がかかります。 – Borealid

4

bは一時的です。テイク20が技術的に範囲外になってから、読み取った内容(印刷時)は読み込まれるまでに無効な場所です。それは未定義の動作です

:矛盾した結果を説明するために

。別のアーキテクチャ用の

  • 変更コンパイラ
  • 変更あなたのコンパイラ設定
  • ビルド
  • 変更あなたのクラスのメンバーのレイアウト
  • 追加またはから物事を削除:あなたがあればあなたは何を参照してください異なる場合がありますxのインスタンスに近いメモリ領域
  • など

常に未定義の動作を避ける必要があります。

なぜ値が変わるのですか?参照は、印刷されるまでに書き換えられた(たとえば再利用された)スタックアドレスを参照している可能性があります。

+0

私は正直なところ、最終的な「なぜ違うのか...」という意味を理解できません。あなたが話していることを正確に指摘できるなら、私はそれを感謝します。なぜなら、最初の「さえ」は、「:」の後に続くものは理にかなっていますが、それほど明確ではありません。 – batbrat

+0

@batbrat expanded – justin

+1

+1いい仕事です!それは今よりずっと良い意味になります。 – batbrat

3

const&を一時的にバインドしていますが、これはコンストラクタの呼び出しを超えては存続しません。 C++ 03標準では、「コンストラクタのctor-initializer(12.6.2)内の参照メンバに一時的にバインドされたものは、コンストラクタが終了するまで保持されます(12.2/5「一時オブジェクト」)。

あなたのコードには定義されていない動作があります。あなたはナンセンスや「動作している」ように見えるかもしれません。

FWIW、MSVC 2010はそのコードに次のような警告提供します:私は私のコンパイラの答えは、このいずれかをもらおう

C:\temp\test.cpp(12) : warning C4413: 'X::b' : reference member is initialized to a temporary that doesn't persist after the constructor exits 
19

を:

$ g++ -std=c++98 -Wall -Wextra -pedantic test.cpp 
test.cpp: In constructor 'X::X()': 
test.cpp:9:26: warning: a temporary bound to 'X::b' only persists until the constructor exits [-Wextra] 
$ 

あなたにあなたのコンパイラの警告をオンにする必要がありますよく

+0

答えをありがとう、なぜ私はbが一時的な初期化ですか?私は初期化リストを通してconst値を初期化しようとしています。 –

+1

@VivekBasappa: 'X :: b'はconst参照であり、const値ではありません。 –

+1

@VivekBasappa 'const'は問題ではありません。問題は参照するものがない* reference *です。 –

関連する問題