来自std::shared_ptr的问题,不仅仅是循环引用
2022-09-05 本文已影响0人
左图右码
《C++标准库,2nd》用father/mother/kids的例子揭示了shared_ptr循环引用所导致的析构失败的问题,见5.2.2。这最多造成memory leak,更致命的是造成app崩溃。如我所遇:
struct displayElementPts
{
static std::shared_ptr< displayElementPts> instance(){...}
void clear(){...}
}
class dialog{
static std::shared_ptr< dialog > instance(){...}
virtual void closeEvent(...){
auto dis = displayElementPts::instance();
dis->clear();
}
}
在dialog关闭的时候,会调用displayElementPts。
一般这是无害的。但退出app的时候,对话框会调用closeEvent ,问题就在这里,如果这个对话框从来就没实例化过,就没问题,如果正在显示,此时退出app,对话框会销毁,并调用closeevent。dialog与displayElementPts一样,也是单例方式创建的实例,由一个静态的std::shared_ptr拥有着,他们的析构次序是不确定的,所以程序会在退出的时候发生随机的崩溃。
轮到std::weak_ptr了,你虽不怎么关注它,或者几乎没用过它,但它并不像名字所示的那么弱。
class dialog{
static std::shared_ptr< dialog > instance(){...}
virtual void closeEvent(...){
if(!m_wp.expired())
m_wp->locked()->clear();
}
dialog()
{
//...
m_wp = displayElementPts::instance();
}
private:
std::weak_ptr< displayElementPts > m_wp;
}
先用expired()判断单实例是否有效,再用locked取得有效的指针。就能避免获取或者不能获取有效实例的问题。
有没有带着镣铐跳舞的感觉,其实不然,只是在特殊的事件里才需要判断,其它的位置,直接调用locked就好了。
请安心享用std::shared_ptr吧。