最后我找到了非常奇怪的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%的次数)会破坏我的真实代码中的事件系统容器,这会导致段错误,但很少会破坏它并且一切正常。
答案 0 :(得分:11)
CTileBrowser构造函数按值获取其参数。您很可能会看到为该构造函数创建的临时副本的销毁。将其更改为参考参数,我敢打赌问题会消失。