2012-03-16 14 views
1

コピーコンストラクタ:ストレージが解放されたら?コードが与えられ

class Sample 
{ 
public: 
     int *ptr; 
     Sample(int i) 
     { 
     ptr = new int(i); 
     } 
     ~Sample() 
     { 
     delete ptr; 
     } 
     void PrintVal() 
     { 
     cout << "The value is " << *ptr; 
     } 
}; 
void SomeFunc(Sample x) 
{ 
    cout << "Say i am in someFunc " << endl; 
} 
int main() 
{ 
    Sample s1= 10; 
    SomeFunc(s1); 
    s1.PrintVal(); 
} 

出力は次のようになります。私は、出力の2行目が来る理由を理解することはできませんよ

Say i am in someFunc 
Null pointer assignment(Run-time error) 

。出力の2行目。私は、コンパイラが明示的に指定されていない場合、コピーコンストラクタを提供すると思います。したがって、SomeFunc(Sample x)関数では、Sample型のXであるSomeFunc()へのローカルオブジェクトを作成して破棄し、main()のSample型オブジェクト(s1)をそのまま残す必要があります。メイン出口。上記の現象が起こっている理由を答えてください。

答えて

6

なぜ上記の現象が起こっていますか?

短い答え:
あなたはRule of Threeを、次のされていませんので。

ロング回答:
あなたのコードは、暗黙的に生成されたコピーコンストラクタを呼び出すことによって機能SomeFunc()に渡しながら、オブジェクトの一時的なコピーを作成しながら、あなたのクラスはデストラクタでコンストラクタと解放の動的なメモリ割り当てを指針部材ptrを持っていますコンパイラによって、ポインタ・メンバのshallow copyが作成されます。関数呼び出しの終わりにテンポラリが破棄されると、メモリはデストラクタで割り当て解除され、ダングリングポインタが残っています。PrintVal()という関数を呼び出すと、この無効なポインタはさらに参照解除され、の未定義動作になります。セグメンテーションフォールトの形式。

この問題を回避するにはどうすればよいですか?

短い答え:
は三つのルールに従ってください。

ロング回答:
あなたはポインタメンバーptrのディープコピーを作成し、コピーコンストラクタを提供する必要があります。これにより、メンバで作成されたオブジェクトのポインタメンバは、プログラムの存続期間中有効になります。

EDIT:、これは、変換コンストラクタを呼び出し

Sample s1= 10; 

Sample(int i) 

を:
実は、問題もあなたが呼ぶ、特にとき、関数が呼び出される前であっても発生する可能性があります一時的なSampleオブジェクトを作成してから、s1オブジェクトの構築に使用されます。このオブジェクトは、暗黙のコピーコンストラクタを呼び出して、この場合、作成されたテンポラリオブジェクトは、s1の作成後に、ポインタメンバptrをダングリング状態のままにしてしまいます。

しかし、コンパイラのほとんどは、このように、したがって、これは問題ではないかもしれませんコピーコンストラクタ&を呼び出す必要がなくなりReturn Value Optimization(RVO)を使用してコピーの省略による最適化を適用します。

どちらの場合でも、問題の解決方法は同じです。

+0

このようなピンポイントの回答をいただきありがとうございます。 :) – Abhay

+0

変換コンストラクタの場合を言及した編集のための+1ですが、それはRVOの原因ではありません。 – Sanish

+0

@Als:今日私は自分のStack Exchangeアカウントを作成しました。応答の迅速さ。 :) – Abhay

関連する問題