目录
目录
C++智能指针循环引用问题分析_swings_ss的博客-CSDN博客
一、介绍
智能指针一共有4个,分别是shared_ptr,unique_ptr,weak_ptr,auto_ptr,最后一个被弃用了,主要是前面三种。
作用是自动回收内存,不需要是delete,原理是智能指针内部有个计数器,每当创建一次对象计数加一,销毁一次计数减一,当计数等于0时自动释放对象。
二、应用场景
1.shared_ptr
多个指针可以指向同一个对象
2.unique_ptr
一个指针只能指向一个对象
#include <iostream>
using namespace std;
class A;
class B;
class B {
public:
B() {
cout << "执行B类的构造函数\n";
}
~B() {
cout << "执行B类的析构函数" << endl;
}
public:
unique_ptr<A>a;
};
class A {
public:
A() {
cout << "执行A类的构造函数\n";
}
~A() {
cout << "执行A类的析构函数" << endl;
}
public:
unique_ptr<B>b;
};
int main()
{
unique_ptr<B>pb(new B);
unique_ptr<A>pa(new A);
//pb->a = pa; //此时会报错
return 0;
}
3.weak_ptr
不能增加或减少shared_ptr的计数,只能对其计数进行访问。
为了解决循环引用导致对象不能通过shared_ptr释放,例如A类包含B类,B类又包含A类,创建后A和B的智能指针计数都为2,释放的时候两个类计数器都为1,不能自动释放,造成内存泄漏。
#include <iostream>
using namespace std;
class A;
class B;
class B {
public:
B() {
cout << "执行B类的构造函数\n";
}
~B() {
cout << "执行B类的析构函数,类A的引用计数为:" << a.use_count() << endl;
}
public:
shared_ptr<A>a;
};
class A {
public:
A() {
cout << "执行A类的构造函数\n";
}
~A() {
cout << "执行A类的析构函数,类B的引用计数为:" << b.use_count() << endl;
}
public:
shared_ptr<B>b;
};
int main()
{
shared_ptr<B>pb(new B);
shared_ptr<A>pa(new A);
pb->a = pa;
pa->b = pb;
//输出pb,pa的计数个数
cout << "pb的计数:" << pb.use_count() << endl;
cout << "pa的计数:" << pa.use_count() << endl;
return 0;
}
此时结束后,每个智能指针计数减一,但是pa和pb的计数减为1,不等于0,因此帮你执行delete,也就不能执行析构函数,所以不能正常释放对象pa,pb,从而造成了内存泄漏。为了解决不能正常释放对象的问题,可以在类A或者类B里使用weak_ptr,它不影响指针的引用计数。
#include <iostream>
using namespace std;
class A;
class B;
class B {
public:
B() {
cout << "执行B类的构造函数\n";
}
~B() {
cout << "执行B类的析构函数,类A的引用计数为:" << a.use_count() << endl;
}
public:
shared_ptr<A>a;
};
class A {
public:
A() {
cout << "执行A类的构造函数\n";
}
~A() {
cout << "执行A类的析构函数,类B的引用计数为:" << b.use_count() << endl;
}
public:
weak_ptr<B>b;
};
int main()
{
shared_ptr<B>pb(new B);
shared_ptr<A>pa(new A);
pb->a = pa;
pa->b = pb;
//输出pb,pa的计数个数
cout << "pb的计数:" << pb.use_count() << endl;
cout << "pa的计数:" << pa.use_count() << endl;
return 0;
}
因为A类里B成员是weak_ptr,所以不增加B类的引用计数,pb=1,程序结束后,计数减一,pb=0,此时在正常执行B类的析构函数,执行B类析构函数的时候,释放B类的成员A,所以A类就似乎减一,pa此时等于1,接着执行释放A类,pa继续减一,pa=0,pb=0.