c++11之weak_ptr 使用介绍

本文详细介绍了C++标准库中的弱智能指针weak_ptr的功能和用途,包括如何使用weak_ptr来避免shared_ptr的循环引用问题,以及通过示例代码展示了weak_ptr的基本操作和应用场景。

介绍

weak_ptr是弱智能指针对象,它不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的智能指针。将一个weak_ptr绑定到一个shared_ptr对象,不会改变shared_ptr的引用计数。一旦最后一个所指向对象的shared_ptr被销毁,所指向的对象就会被释放,即使此时有weak_ptr指向该对象,所指向的对象依然被释放。

这里写图片描述

代码验证如下:

//default consstructor
weak_ptr<string> wp;

{
    shared_ptr<string> p = make_shared<string>("hello world!\n");
    //weak_ptr对象也绑定到shared_ptr所指向的对象。
    wp = p;   
    cout << "use_count: " <<wp.use_count() << endl;
}
//wp是弱类型的智能指针,不影响所指向对象的生命周期,
//这里p已经析构,其所指的对象也析构了,因此输出是0
cout << "use_count: " << wp.use_count() << endl;

运行结果:

use_count: 1
use_count: 0

weak_ptr智能指针使用如下

void test_valid(weak_ptr<string> &wp)
{
    if(shared_ptr<string>  smptr2 = wp.lock())
    {
        cout << "the shared_ptr is valid\n";
    }
    else
    {
        cout << "the shared_ptr is not valid\n";
    }

    //检查被引用的对象是否已删除 false 仍存在  true 释放
    if(!wp.expired())
    {
        //it is getting valid shared_ptr obj now;
        shared_ptr<string>  smptr1 = wp.lock();
        cout << "   get obj value: " << *smptr1;
    }
}

int main()
{    
    shared_ptr<string> p = make_shared<string>("hello world!\n");

    //default consstructor
    weak_ptr<string> wp1;

    //copy constructor
    weak_ptr<string> wp2(p);

    //assign constructor
    weak_ptr<string> wp3 = wp2;

    test_valid(wp2);

    //释放被管理对象的所有权, 调用后 *this 不管理对象
    wp2.reset();

    test_valid(wp2);

    return 0;
}

运行结果:

the shared_ptr is valid
    get obj value: hello world!
the shared_ptr is not valid

循环引用

weak_ptr可以解决shared_ptr循环引用问题,导致内存泄漏问题,问题模型如下图:

这里写图片描述

当shared_ptr类型的spA、spB对象析构时,ref_count 减一;由于Obj A 和 Obj B中的shared_ptr智能指针还相互引用,导致ref_count不为零,spA和spB不会去析构所指的对象,最终导致内存泄漏。

当Obj A 和 Obj B中的智能指针是weak_ptr是,不会影响share_ptr智能指针引用计数,当spA和spB析构时,导致ref_count为零,同时所指向的对象也就被析构了;其解决方案模型如下:
这里写图片描述

代码实例如下:

//strong reference
class B;
class A
{
public:
    shared_ptr<class B> m_spB;
};


class B
{
public:
    shared_ptr<class A> m_spA;
};

//weak reference
class WeakB;
class WeakA
{
public:
    weak_ptr<class WeakB> m_wpB;
};


class WeakB
{
public:
    weak_ptr<class WeakA> m_wpA;
};


void test_loop_ref()
{
    weak_ptr<class A> wp1;

    {
        auto pA = make_shared<class A>();
        auto pB = make_shared<class B>();

        pA->m_spB = pB;
        pB->m_spA = pA;

        wp1 = pA;    
    }//内存泄漏

    cout << "wp1 reference number: " << wp1.use_count() << "\n";

    weak_ptr<class WeakA> wp2;
    {
        auto pA = make_shared<class WeakA>();
        auto pB = make_shared<class WeakB>();

        pA->m_wpB = pB;
        pB->m_wpA = pA;

        wp2 = pA;
    }//无内存泄漏

    cout << "wp2 reference number: " << wp2.use_count() << "\n";
}

int main()
{    
    //std::weak_ptr 用来避免 std::shared_ptr 的循环引用
    test_loop_ref();

    return 0;
}

wp1和wp2作为shared_ptr智能指针的核查器,其检测结果如下:

wp1 reference number: 1//内存泄漏
wp2 reference number: 0//问题解决
C++11 引入的 `std::weak_ptr` 是一种非拥有型智能指针,与 `std::shared_ptr` 配合使用,用于解决共享所有权场景下的循环引用问题,本身不拥有对象的所有权,仅提供对 `shared_ptr` 管理对象的临时访问能力,不会影响对象的生命周期 [^2]。 ### 引入背景 `shared_ptr` 通过引用计数解决了指针独占的问题,但会产生引用成环问题,导致内存泄漏。`weak_ptr` 就是为弥补 `shared_ptr` 这一缺陷而引入标准库的 [^1]。 ### 核心优势 1. **打破循环引用**:解决 `shared_ptr` 形成的循环引用导致的内存泄漏 [^2]。 2. **非侵入式观察**:不增加引用计数,不影响对象的销毁时机 [^2]。 3. **安全访问**:提供 `lock()` 方法安全获取对象访问权,避免悬垂指针 [^2]。 4. **轻量级设计**:仅需存储控制块指针,开销小 [^2]。 ### 创建方式 - **创建空的 `weak_ptr`**:创建一个不指向任何对象的 `weak_ptr` [^3]。 - **拷贝构造函数创建 `weak_ptr`**:用一个已有的 `weak_ptr` 来创建新的 `weak_ptr` [^3]。 - **利用已有的 `shared_ptr` 指针创建 `weak_ptr`**:将 `weak_ptr` 绑定到一个 `shared_ptr` 上,不会改变 `shared_ptr` 的引用计数 [^3][^4]。 ### 成员方法 `weak_ptr` 提供了一些成员方法,其中 `lock()` 方法较为重要,它可以安全地获取对象访问权。当调用 `lock()` 时,如果 `weak_ptr` 所指向的对象仍然存在(即对应的 `shared_ptr` 还在管理该对象),则返回一个指向该对象的 `shared_ptr`;如果对象已经被销毁,则返回一个空的 `shared_ptr`,从而避免了悬垂指针的问题 [^2]。 ### 示例代码 ```cpp #include <iostream> #include <memory> class B; class A { public: std::shared_ptr<B> b_ptr; ~A() { std::cout << "A destroyed" << std::endl; } }; class B { public: std::weak_ptr<A> a_ptr; // 使用 weak_ptr 打破循环引用 ~B() { std::cout << "B destroyed" << std::endl; } }; int main() { std::shared_ptr<A> a = std::make_shared<A>(); std::shared_ptr<B> b = std::make_shared<B>(); a->b_ptr = b; b->a_ptr = a; return 0; } ``` 在上述代码中,`class B` 中的 `a_ptr` 使用了 `std::weak_ptr`,避免了 `A` 和 `B` 之间的循环引用。当 `main` 函数结束时,`a` 和 `b` 的引用计数减为 0,`A` 和 `B` 对象会被正确销毁。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值