最後に、二重呼び出しデストラクタによって引き起こされる非常に奇妙なバグを突き止めました。バグを再現する最小限のコードは次のとおりです。
#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 であることを示しています。
不要なデストラクタ呼び出しの原因と、それを取り除くにはどうすればよいですか? 私は c++11 フラグで g++4.7 を使用しています。
問題は、通常(90% の確率で)不要なデストラクタ呼び出しによって実際のコードのイベント システム コンテナーが破損し、セグメンテーション違反が発生することですが、めったに破損せず、すべてが機能します。