使用shared_ptr时调用奇怪的双析构函数

时间:2013-02-06 23:19:03

标签: c++ c++11 g++ destructor shared-ptr

最后我找到了非常奇怪的bug,这是由双重调用析构函数引起的。这是重现错误的最小代码:

#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%的次数)会破坏我的真实代码中的事件系统容器,这会导致段错误,但很少会破坏它并且一切正常。

1 个答案:

答案 0 :(得分:11)

CTileBrowser构造函数按值获取其参数。您很可能会看到为该构造函数创建的临时副本的销毁。将其更改为参考参数,我敢打赌问题会消失。