C++ 中 shared_ptr 对象之间可以共享对象的拥有权,但是这种共享的对象引用在某些情况下可能会引发一些问题。例如,循环引用会造成两个对象之间相互引用,无法删除对象。
一个循环引用的例子
class bar;
class foo
{
public:
foo()
{
}
std::shared_ptr<bar> ptr_bar;
~foo()
{
std::cout << "foo destructed"<<std::endl;
}
};
class bar
{
public:
bar()
{
}
std::shared_ptr<foo> ptr_foo;
~bar()
{
std::cout << "bar destructed" << std::endl;
}
};
int main(int argc,const char* argv[])
{
std::shared_ptr<foo> f = std::make_shared<foo>();
std::shared_ptr<bar> b = std::make_shared<bar>();
f->ptr_bar = b;
b->ptr_foo = f;
std::cout << "foo's count is " << f.use_count() << std::endl;
std::cout << "bar's count is " << b.use_count() << std::endl;
}
//output
//foo's count is 2
//bar's count is 2
可以看到,并没有出现析构器中应该打印的信息,这说明我们构造的对象并没有被析构,那么内存便泄漏了。那么造成该现象的原因是什么呢?
std::shared_ptr 使用了引用计数算法,每当一个 std::shared_ptr 对象引用一个对象,那么会在对应的控制块中将引用计数加一,当 std::shared_ptr 对象被析构时,引用计数会减一。如果计数等于零,那么将会删除该对象。
在 main 函数里面,我们通过 std::make_shared 函数分别构造了 std::shared_ptr
当退出 main 函数的时候,f 和 b 对象都会析构。f 和 b 对象析构时都会将引用计数减一。这里就是问题所在,此时 foo 对象和 bar 对象的引用计数为一,无法达到零,导致 foo 对象和 bar 对象永远无法被删除。
利用 std::weak_ptr 打破循环引用
上述的循环引用可以通过std::weak_ptr来解决。修改的代码如下
class bar;
class foo
{
public:
foo()
{
}
std::weak_ptr<bar> ptr_bar;
~foo()
{
std::cout << "foo destructed"<<std::endl;
}
};
class bar
{
public:
bar()
{
}
std::weak_ptr<foo> ptr_foo;
~bar()
{
std::cout << "bar destructed" << std::endl;
}
};
int main(int argc,const char* argv[])
{
std::shared_ptr<foo> f = std::make_shared<foo>();
std::shared_ptr<bar> b = std::make_shared<bar>();
f->ptr_bar = b;
b->ptr_foo = f;
std::cout << "foo's count is " << f.use_count() << std::endl;
std::cout << "bar's count is " << b.use_count() << std::endl;
}
//output
//foo's count is 1
//bar's count is 1
//bar destructed
//foo destructed
可以看到 std::weak_ptr 并没有给引用计数加一,实际上它增加的是控制块的弱引用计数。当 std::weak_ptr 的析构器被调用的时候,它会将弱引用计数减一,如果弱引用计数等于零,那么会删除控制块。其实也不一定需要 foo 和 bar 类中都是 std::shared,只要其中之一是 std::weak_ptr 即可。
原文链接: https://www.cnblogs.com/riasartemis/p/17099954.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/316459
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!