C++中双斜杠//只能注释一行,在这里我没有花时间排版,所以看起来//注释换了行。把代码复制到编辑器或IDE上看可能会好很多。
weak_ptr指向一个shared_ptr管理的对象,最重要的特点就是,weak_ptr不会改变shared_ptr的引用计数。weak_ptr更详细的介绍可以参考《C++ Primer》中文版第五版第420页。此篇文章将给出《C++ Primer》上没有给出的weak_ptr的用法。
weak_ptr指向一个shared_ptr管理的对象,最重要的特点就是,weak_ptr不会改变shared_ptr的引用计数。weak_ptr更详细的介绍可以参考《C++ Primer》中文版第五版第420页。此篇文章将给出《C++ Primer》上没有给出的weak_ptr的用法。
在使用shared_ptr的时候,可能会出现环形引用的问题。一旦出现了环形引用(Circular Reference),就会导致两个shared_ptr的引用计数都没办法减到1,也就没办法销毁对象,程序结束的时候就没办法正常地释放内存。下面将演示一下这种情况。
#include<memory> //shared_ptr定义在memory头文件中。
using namespace std;
//我们先定义一个叫Node的类,包含两个数据成员。
struct Node{
shared_ptr<Node> previous;
shared_ptr<Node> next;
};
int mian()
{
//然后在main函数里定义两个指向Node类对象的shared_ptr并进行值初始化。
shared_ptr<Node> n1 = make_shared<Node>(); //此时n1计数器为1。
shared_ptr<Node> n2 = make_shared<Node>(); //此时n2计数器为1。
//不妨假设n1指向的对象名字为node_1,n2指向的叫node_2。
//接下来让node_1的next成员指向node_2,让node_2的previous成员指向node_1。
(*n1).next=n2; //拷贝了n2,此时n2的计数器为2
(*n2).previous=n1; //拷贝了n1,此时n1的计数器为2
//这时n1、n2就产生了环形引用。
return 0;
}
创建n1并且值初始化时,n1的计数器就变成了1,然后给node_2.previous赋值为node_1的拷贝的时候,node_1被拷贝了一次,因此n1计数器加1,此时计数器为2。同理,n2的计数器也变为了2。如图,此时两个对象就产生了环形引用。
1.当我们要 delete n1 的时候,就必须把n1的计数器减为1。
2.想要把n1的计数器减为1,就必须把node_2.previous销毁。
3.想要销毁node_2.previous,就必须 delete n2 。
4.想要 delete n2 ,就必须把n2的计数器减为1。
5.想要把n2的计数器减为1,就必须把node_1.next销毁。
6.想要销毁node_1.next,就必须 delete n1 。
7.想要 delete n1 ,就又回到了第一行,进入了死循环。
这就是shared_ptr智能指针的环形引用问题,两个陷入环形引用的shared_ptr永远没办法delete。解决方案就是,改用weak_ptr。下面是演示。
#include<memory> //shared_ptr定义在memory头文件中。
using namespace std;
//我们先定义一个叫Node的类,包含两个数据成员。
struct Node{
weak_ptr<Node> previous;
weak_ptr<Node> next;
};
int mian()
{
shared_ptr<Node> n1 = make_shared<Node>(); //此时n1计数器为1。
shared_ptr<Node> n2 = make_shared<Node>(); //此时n2计数器为1。
(*n1).next=n2; //拷贝了n2,此时n2的计数器仍为1。
(*n2).previous=n1; //拷贝了n1,此时n1的计数器仍为1。
return 0;
}
虽然也是环形引用,可是用的是weak_ptr而非shared_ptr,weak_ptr不会改变shared_ptr的引用计数,因此n1、n2的计数仍为1,从而可以正常进行delete。
Comments
Post a Comment