2013-02-06 11 views
5

最後に、デストラクタを二重に呼び出すことによって引き起こされた非常に奇妙なバグを追跡しました。ここでバグを再現する最小限のコードは次のとおりです。shared_ptrを使用すると奇妙なダブルデストラクタコール

#include <iostream> 
#include <memory> 
#include <set> 

class cEventSystem { 
    public: 
     cEventSystem() { 
      std::cout << "constructor: " << this << std::endl; 
     } 
     ~cEventSystem() { 
      std::cout << "destructor: " << this << std::endl; 
     } 
}; 

class cSubscriber { 
    public: 
     cSubscriber(cEventSystem& eventSystem) : eventSystem(eventSystem) {} 
     virtual ~cSubscriber() {} 
     virtual void onEvent() = 0; 
    protected: 
     cEventSystem& eventSystem; 
}; 

class cTileBrowser: public cSubscriber { 
    public: 
     cTileBrowser(cEventSystem eventSystem) : cSubscriber(eventSystem) {} 
     void onEvent() {} 
}; 

class cGui: public cSubscriber { 
    public: 
     cGui(cEventSystem& eventSystem) : cSubscriber(eventSystem) { 
      tileBrowser = std::make_shared<cTileBrowser>(eventSystem); 
     } 
     void onEvent() {} 
     std::shared_ptr<cTileBrowser> tileBrowser; 
}; 

int main() { 
    cEventSystem eventSystem; 
    cGui gui(eventSystem); 
} 

出力は次のとおりです。

constructor: 0x7fffffffe67f 
destructor: 0x7fffffffe2df 
destructor: 0x7fffffffe67f 

あなたが最初のデストラクタが不要であり、それがで構築されていなかった別のオブジェクトで呼び出される見ることができるようにすべて(住所は違う)、私の実際のコードでは住所は十分に近く、私がイベントシステムに持っているコンテナを壊す。

デバッグは、そのデストラクタコールを引き起こすmake_sharedであることを示しています。

この不要なデストラクタコールはどのような原因で削除されますか? g ++ 4.7とC++ 11フラグを使用します。

通常は(90%の時間)は、segfaultsの原因となる実際のコードで自分のイベントシステムコンテナを破損しますが、まれに破損せずすべてが機能します。

答えて

11

CTileBrowserコンストラクタは値で引数を受け取ります。あなたは、そのコンストラクタのために作成された一時的なコピーが破損している可能性が高いです。それを参照パラメータに変更して、問題がなくなると思います。

+0

男、あなたはヒーローです、それは今私の本当のコードで動作します!しかし、なぜ一時的なコピーがそれがメモリ内の私のデータを壊すことができないほど安全でないのですか?私はほとんどいつも参照(これは間違いだった)によって渡すが、少なくとも私には奇妙に思える。 – user1873947

+2

@ user1873947、コピーコンストラクタはコンパイラによって生成されているため、おそらく間違ったことをしています。例えばポインタのコピーを作成し、デストラクタがそれを削除すると、元のオブジェクトにぶら下がったポインタが残ってしまいます。 –

+0

@Mark Ransomそれです。私の実際のコードでは、私はポインタのセットを持っています。 – user1873947

関連する問題