如何修复此 shared_ptr 个引用循环?
How to fix this shared_ptr reference cycles?
我设计了一个 App
来容纳一堆 layers
和一个活跃的 obj
。
当 Layer
附加到 App
时,Layer
告诉 App
什么是活动的 object
。但是我的设计在解除分配时会导致信号陷阱。
它导致 sigtrap,因为 App 中 shared_ptr<Obj> m_obj
的破坏首先发生,将 use_count
减少为 1。然后调用 onDetech
函数,设置活动 shared_ptr<Obj> m_obj
到 nullptr
并将 use_count
减少到 0!但是 layer
仍然持有 shared_ptr<Obj>
.
下面的代码是一个最小的重现示例。我注意到我的代码有一个引用循环,但我不知道如何解决这个问题,除了在 App
class.
中使用 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
运行
m_activeObj
被摧毁;在此之后它的生命周期结束并且无法再访问
m_defaultLayer
被摧毁
m_stack
被摧毁
m_layers[0].onDetach()
被称为
onDetach
将 m_app->m_activeObj
设置为 nullptr
,但其生命周期已经结束,因此行为未定义。
- 其他不相关的东西;你已经完蛋了。
解决方案是重新排序,这样您就不会在其生命周期结束后访问 m_activeObj
。要么将 m_stack
的声明移动到 m_activeObj
之后,以便它首先被销毁,要么在 ~App
.
中手动清除它
我设计了一个 App
来容纳一堆 layers
和一个活跃的 obj
。
当 Layer
附加到 App
时,Layer
告诉 App
什么是活动的 object
。但是我的设计在解除分配时会导致信号陷阱。
它导致 sigtrap,因为 App 中 shared_ptr<Obj> m_obj
的破坏首先发生,将 use_count
减少为 1。然后调用 onDetech
函数,设置活动 shared_ptr<Obj> m_obj
到 nullptr
并将 use_count
减少到 0!但是 layer
仍然持有 shared_ptr<Obj>
.
下面的代码是一个最小的重现示例。我注意到我的代码有一个引用循环,但我不知道如何解决这个问题,除了在 App
class.
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
运行m_activeObj
被摧毁;在此之后它的生命周期结束并且无法再访问m_defaultLayer
被摧毁m_stack
被摧毁m_layers[0].onDetach()
被称为onDetach
将m_app->m_activeObj
设置为nullptr
,但其生命周期已经结束,因此行为未定义。
- 其他不相关的东西;你已经完蛋了。
解决方案是重新排序,这样您就不会在其生命周期结束后访问 m_activeObj
。要么将 m_stack
的声明移动到 m_activeObj
之后,以便它首先被销毁,要么在 ~App
.