C++智能指针的使用[转载]

\(reference1\)
\(reference2\)

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_prtmain中的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

1
2

posted @ 2024-03-17 15:34  光風霽月  阅读(1)  评论(0编辑  收藏  举报