如何修复此shared_ptr引用周期



我设计了一个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的生存期结束后访问它,因此程序的行为是未定义的。

事件顺序如下:

  1. App对象超出范围
  2. ~App运行
  3. CCD_ 28被破坏;在此之后,它的生命周期结束,无法再访问
  4. m_defaultLayer被破坏
  5. m_stack被破坏
    1. m_layers[0].onDetach()被调用
    2. onDetachm_app->m_activeObj设置为nullptr,但其生存期已结束,因此行为未定义
  6. 无关的其他东西;你已经完蛋了

解决方案是重新排序,这样在m_activeObj的使用寿命结束后就不会访问它。将m_stack的声明移动到m_activeObj之后,使其首先被销毁,或者在~App中手动清除它。

相关内容

  • 没有找到相关文章

最新更新