返回

C++ weak_ptr的使用

发布时间:2022-10-14 21:36:09 247
# c++# ios

这是一篇关于讲解关于weak_ptr使用的问题,在c++11被引入,weak_ptr也是c++11智能指针的一种,是为了解决shared_ptr循环引用的问题而引入。

1. 循环引用导致的问题

循环引用,简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方的会造成循环引用,导致引用计数失效。

#include 
#include 

class classB;
class classA {
public:
    classA() {
        std::cout << "classA()" << std::endl;
    }
    ~classA() {
        std::cout << "~classA()" << std::endl;
    }
    void set_ptr(std::shared_ptr& ptr) {
        std::cout << "在类A中,拷贝之前m_ptr_b的引用次数为" << m_ptr_b.use_count() << std::endl;
        m_ptr_b = ptr;
        std::cout << "在类A中,拷贝之后m_ptr_b的引用次数为" << m_ptr_b.use_count() << std::endl;
    }
private:
    std::shared_ptr m_ptr_b;
};

class classB {
public:
    classB() {
        std::cout << "classB()" << std::endl;
    }
    ~classB() {
        std::cout << "~classB()" << std::endl;
    }
    void set_ptr(std::shared_ptr& ptr) {
        std::cout << "在类B中,拷贝之前m_ptr_a的引用次数为" << m_ptr_a.use_count() << std::endl;
        m_ptr_a = ptr;
        std::cout << "在类B中,拷贝之后m_ptr_a的引用次数为" << m_ptr_a.use_count() << std::endl;
    }
private:
    std::shared_ptr m_ptr_a;
};

int main()
{
    std::shared_ptr ptr_a(new classA());  //调用类A构造函数,此时ptr_a的引用计数已经加1
    std::cout << "new 完之后 ptr_a的引用计数为" << ptr_a.use_count() << std::endl;
    std::shared_ptr ptr_b(new classB());    //调用类B构造函数,此时ptr_b的引用计数已经加1
    std::cout << "new 完之后 ptr_b的引用计数为" << ptr_b.use_count() << std::endl;
    ptr_a->set_ptr(ptr_b);  //set内部会发生拷贝动作,导致智能指针的引用计数加1,
    ptr_b->set_ptr(ptr_a);
    std::cout << ptr_a.use_count() << " " << ptr_b.use_count() << std::endl;
    system("pause");
    return 0;
}

可以看到,上述代码执行完之后,没有执行类A和类B的析构函数。与代码分析类似,由于引用计数的值在退出main函数之前没有减到1,因此也没执行对象的析构函数。

2.使用weak_ptr解决循环引用不析构的问题

将上述代码中类A和类B成员中的智能指针换为weak_ptr可以解决,如下代码

#include 
#include 

class classB;
class classA {
public:
    classA() {
        std::cout << "classA()" << std::endl;
    }
    ~classA() {
        std::cout << "~classA()" << std::endl;
    }
    void set_ptr(std::shared_ptr& ptr) {
        std::cout << "在类A中,拷贝之前m_ptr_b的引用次数为" << m_ptr_b.use_count() << std::endl;
        m_ptr_b = ptr;
        std::cout << "在类A中,拷贝之后m_ptr_b的引用次数为" << m_ptr_b.use_count() << std::endl;
    }
private:
    std::weak_ptr m_ptr_b;
};

class classB {
public:
    classB() {
        std::cout << "classB()" << std::endl;
    }
    ~classB() {
        std::cout << "~classB()" << std::endl;
    }
    void set_ptr(std::shared_ptr& ptr) {
        std::cout << "在类B中,拷贝之前m_ptr_a的引用次数为" << m_ptr_a.use_count() << std::endl;
        m_ptr_a = ptr;
        std::cout << "在类B中,拷贝之后m_ptr_a的引用次数为" << m_ptr_a.use_count() << std::endl;
    }
private:
    std::weak_ptr m_ptr_a;
};

int main()
{
    std::shared_ptr ptr_a(new classA());  //调用类A构造函数,此时ptr_a的引用计数已经加1
    std::cout << "new 完之后 ptr_a的引用计数为" << ptr_a.use_count() << std::endl;
    std::shared_ptr ptr_b(new classB());    //调用类B构造函数,此时ptr_b的引用计数已经加1
    std::cout << "new 完之后 ptr_b的引用计数为" << ptr_b.use_count() << std::endl;
    ptr_a->set_ptr(ptr_b);  //set内部会发生拷贝动作,导致智能指针的引用计数加1,
    ptr_b->set_ptr(ptr_a);
    std::cout << ptr_a.use_count() << " " << ptr_b.use_count() << std::endl;
    system("pause");
    return 0;
}

- [] 使用weak_ptr建立的引用不会导致引用计数的增加

3.weak_ptr的原理

weak_ptr只是指向shared_ptr对象的一个指针,它可以从一个shared_ptr或者weak_ptr构造而来,但是weak_ptr的构造和析构不会引起shared_ptr的引用计数的增减。weak_ptr是shared_ptr的一个助手。

4.使用weak_ptr需要注意

weak_ptr并不改变其所共享的shared_ptr实例的引用计数,可能存在weak_ptr指向的对象被释放掉这种情况。这时,就不能使用weak_ptr直接访问对象。那么如何判断weak_ptr指向对象是否存在呢?C++中提供了lock函数来实现该功能。如果对象存在,lock()函数返回一个指向共享对象的shared_ptr(引用计数会增1),否则返回一个空shared_ptr。weak_ptr还提供了expired()函数来判断所指对象是否已经被销毁.

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线