C++智能指针的使用[转载]
shared_ptr
循环引用
#include <iostream>
#include <cstring>
#include <algorithm>
#include <memory>
using namespace std;
struct B;
struct A;
struct A {
shared_ptr<B> a;
~ A (){
cout << "deleteA\n";
}
};
struct B {
shared_ptr<A> b;
~ B (){
cout << "deleteB\n";
}
};
int main()
{
auto pa = make_shared<A>();
auto pb = make_shared<B>();
pa->a = pb;
pb->b = pa;
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
// 此时pa和pb循环引用,都不会释放
return 0;
}
\(why\) \(need\) std::enable_shared_from_this
看下面的例子:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <memory>
using namespace std;
struct A {
int val = 123;
~A() {
cout << "deleteA: " << val << endl;
}
void func() {
shared_ptr<A> local_sp_a(this);
cout << "[func]use_count: " << local_sp_a.use_count() << endl;
// do something
}// 在这里,func结束之后,local_sp_a会对this,即a执行delete操作
};
int main()
{
A* a = new A();
// 将a对象交给shared_ptr管理
std::shared_ptr<A> sp_a(a);
cout << "[before_func]use_count: " << sp_a.use_count() << endl;
sp_a->func();
cout << "[after_func]sp_a.use_count: " << sp_a.use_count() << endl;
return 0;
// 在main结果之后,sp_a会对a执行delete操作
}
输出:
[before_func]use_count: 1
[func]use_count: 1
deleteA: 123
[after_func]sp_a.use_count: 1
deleteA: 0
在上面的代码中,我们对 a
执行了两次 \(delete\) 操作,显然不对,问题在于:简而言之,func
中的shared_prt
和main
中的shared_ptr
互相不可见,它们虽然共享同一个对象 a
,但各自拥有的独立的计数器。
补充:对于一个
class/struct
对象,如果它分配在栈上,那么当它的生存周期结束时,会自动调用 \(delete\),但如果它分配在堆上,就不会自动调用 \(delete\),但如果我们用智能指针来管理裸指针,智能指针会帮助我们调用 \(delete\)
那么如何解决上面的问题呢?当我们在对象内部获取该对象自身的 shared_ptr
时,那么该类必须继承 std::enable_shared_from_this<T>
,通过 shared_from_this()
来获得该对象,这个类本质上会给被管理的 \(object\) 上加一个指向计数器的 \(weak ptr\),于是就可以正确地增加引用计数而不是搞出 \(2\) 个独立的计数器。
代码改写为:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <memory>
using namespace std;
struct A : public std::enable_shared_from_this<A> {
int val = 123;
~A() {
cout << "deleteA: " << val << endl;
}
void func() {
shared_ptr<A> local_sp_a = shared_from_this();
cout << "[func]use_count: " << local_sp_a.use_count() << endl;
// do something
}// 在这里,func结束之后,local_sp_a会对this,即a执行delete操作
};
int main()
{
A* a = new A();
// 将a对象交给shared_ptr管理
std::shared_ptr<A> sp_a(a);
cout << "[before_func]use_count: " << sp_a.use_count() << endl;
sp_a->func();
cout << "[after_func]sp_a.use_count: " << sp_a.use_count() << endl;
return 0;
// 在main结果之后,sp_a会对a执行delete操作
}
执行结果为:
[before_func]use_count: 1
[func]use_count: 2
[after_func]sp_a.use_count: 1
deleteA: 123
可以看到,\(delete\) 只执行了一次,在 func()
中,智能指针的计数器的值为 \(2\)。
shared_from_this()
会查找当前对象控制块,然后创建一个新的std::shared_ptr
关联这个控制块。用这个函数之前,是假设当前对象已经存在一个关联的控制块。因此,必须已经存在一个指向当前对象的std::shared_ptr
。如果没有std::shared_ptr
指向当前对象(即当前对象没有关联控制块),那么shared_from_this
会抛出一个异常。
作者:孔洽孔洽
链接:https://www.zhihu.com/question/30957800/answer/2700292012
enable_shared_from_this
的核心原理就是在其内部保存一个对this
的弱引用,然后通过这个弱引用构造shared_ptr