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即可。
标签:std,bar,C++,引用,shared,共享,foo,ptr,指针 From: https://www.cnblogs.com/riasartemis/p/17099954.html