5

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

#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% の確率で)不要なデストラクタ呼び出しによって実際のコードのイベント システム コンテナーが破損し、セグメンテーション違反が発生することですが、めったに破損せず、すべてが機能します。

4

1 に答える 1

11

CTileBrowser コンストラクターは、その引数を値で取得しています。そのコンストラクター用に作成された一時コピーが破棄されている可能性があります。それを参照パラメーターに変更すると、問題が解決するはずです。

于 2013-02-06T23:21:49.617 に答える