智能指针的交叉引用问题
- shared_ptr:强智能指针 — 可以改变资源的引用计数
- weak_ptr:弱智能指针 — 不会改变资源的引用计数(“观察者”)
#include <iostream>
#include <memory>
using namespace std;
class B; // 前置声明
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
shared_ptr<B> _ptrb;
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
shared_ptr<A> _ptra;
};
int main()
{
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb = pb;
pb->_ptra = pa;
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
return 0;
}
- 以上代码输出
A() B() 2 2
,显然强智能指针管理的资源未能释放,这是因为程序结束时,强智能指针管理的资源计数-1不为0,因此无法释放。(shared_ptr交叉引用会导致new的资源无法释放,进而造成资源泄露。)
如何解决交叉引用造成的资源泄露问题?
注意到弱智能指针weak_ptr
并不会改变资源的引用计数,相当于“观察者”,故可以采用弱智能指针来解决交叉引用问题。
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
weak_ptr<B> _ptrb; // 弱智能指针不会改变资源的引用计数
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
weak_ptr<A> _ptra; // 弱智能指针不会改变资源的引用计数
};
int main()
{
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb = pb;
pb->_ptra = pa;
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
return 0;
}
- 将强智能指针换为弱智能指针后,成功解决资源泄露问题!(即定义对象时用强智能指针;引用对象的地方使用弱智能指针)
弱智能指针如何调用其它类中的方法?
实际场景中,利用弱智能指针的特性解决了资源泄露问题,但是类B想通过智能指针调用类A中的一个方法,并不能直接调用,因为弱智能指针weak_ptr
只能观察资源,而无法使用资源。
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void testA() { cout << "testA()" << endl; }
weak_ptr<B> _ptrb;
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
void func()
{
// _ptra->testA(); // 弱智能指针无法直接使用资源
shared_ptr<A> ps = _ptra.lock(); // 提升方法
if (ps != nullptr) // 提升成功!
{
ps->testA();
}
}
weak_ptr<A> _ptra;
};
int main()
{
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb = pb;
pb->_ptra = pa;
pb->func();
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
return 0;
}
- 将
weak_ptr
提升为shared_ptr
以调用方法,使用_ptr.lock()
进行提升,并判断是否提升成功,提升成功则可以顺利调用!