我设计了一个App
,它包含一堆layers
和一个活动的obj
。当Layer
连接到App
时,Layer
告诉App
什么是活动的object
。但我的设计在解除分配时会导致sigtrap。
它导致sigtrap,因为首先发生的是应用程序中shared_ptr<Obj> m_obj
的破坏,使use_count
减少到1。然后调用onDetech
函数,将活动的shared_ptr<Obj> m_obj
设置为nullptr
,并将use_count
减小为0!但是CCD_ 15仍然保持一个CCD_。
下面的代码是要复制的最小示例。我注意到我的代码有一个引用循环,但除了在App
类中使用obj
的原始指针外,我不知道如何解决这个问题。
我在App
中使用shared_ptr
代替obj
,因为App
具有obj
的共享所有权对我来说是有意义的。在这种情况下,我不应该使用shared_ptr
吗?
class App;
class Obj {
public:
~Obj() { std::cout << "obj destruct" << std::endl; }
};
class Layer {
public:
Layer() { m_obj = std::make_shared<Obj>(); }
~Layer() { std::cout << m_obj.use_count() << std::endl; }
void onAttach(App *app);
void onDetach();
std::shared_ptr<Obj> m_obj;
private:
App *m_app;
};
class LayerStack {
public:
void pushLayer(App *app, std::shared_ptr<Layer> layer) {
m_layers.push_back(layer);
layer->onAttach(app);
}
~LayerStack() {
for (auto &layer : m_layers) {
layer->onDetach();
}
}
private:
std::vector<std::shared_ptr<Layer>> m_layers;
};
class App {
public:
App() {
m_defaultLayer = std::make_shared<Layer>();
m_stack.pushLayer(this, m_defaultLayer);
}
~App() {}
LayerStack m_stack;
std::shared_ptr<Layer> m_defaultLayer;
std::shared_ptr<Obj> m_activeObj;
};
void Layer::onAttach(App *app) {
m_app = app;
app->m_activeObj = m_obj;
std::cout << m_obj.use_count() << std::endl;
}
void Layer::onDetach() {
m_app->m_activeObj = nullptr;
std::cout << m_obj.use_count() << std::endl;
}
int main() {
A a;
}
输出:
2
obj destruct
-923414512
-923414512
您在m_activeObj
的生存期结束后访问它,因此程序的行为是未定义的。
事件顺序如下:
App
对象超出范围~App
运行- CCD_ 28被破坏;在此之后,它的生命周期结束,无法再访问
m_defaultLayer
被破坏m_stack
被破坏m_layers[0].onDetach()
被调用onDetach
将m_app->m_activeObj
设置为nullptr
,但其生存期已结束,因此行为未定义
- 无关的其他东西;你已经完蛋了
解决方案是重新排序,这样在m_activeObj
的使用寿命结束后就不会访问它。将m_stack
的声明移动到m_activeObj
之后,使其首先被销毁,或者在~App
中手动清除它。