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 回答