为什么要引入 weak_ptr,如果没有它会怎么样(C++代码示例讲解)

为什么要用 std::weak_ptr

std::weak_ptr 主要用于解决 std::shared_ptr 的循环引用问题,这是使用 std::shared_ptr 管理对象生命周期时可能遇到的一个严重问题。

一、循环引用问题

当两个或多个对象相互持有 std::shared_ptr 指向对方时,会产生循环引用。这种情况下,即使没有任何外部 std::shared_ptr 实例引用这些对象,它们仍然无法被销毁,从而导致内存泄漏。

示例代码(循环引用问题):

#include <iostream>
#include <memory>

class B; // 前向声明

class A 
{
public:
    std::shared_ptr<B> ptrB;
    ~A() { std::cout << "A destroyed" << std::endl; }
};

class B 
{
public:
    std::shared_ptr<A> ptrA;
    ~B() { std::cout << "B destroyed" << std::endl; }
};

int main() 
{
    {
        auto a = std::make_shared<A>();
        auto b = std::make_shared<B>();
        a->ptrB = b;
        b->ptrA = a;
    } // 离开作用域时,a和b的析构函数不会被调用,造成内存泄漏

    return 0;
}

输出:

(没有输出,因为对象未被销毁)

在上述代码中,ab 互相持有对方的 std::shared_ptr,因此它们的引用计数始终为1,导致它们的析构函数无法被调用,从而导致内存泄漏。

二、使用 std::weak_ptr 解决循环引用

使用 std::weak_ptr 可以打破这种循环引用。在上面的例子中,我们可以将其中一个对象的 std::shared_ptr 替换为 std::weak_ptr

示例代码(使用 std::weak_ptr 解决循环引用):

#include <iostream>
#include <memory>

class B; // 前向声明

class A 
{
public:
    std::shared_ptr<B> ptrB;
    ~A() { std::cout << "A destroyed" << std::endl; }
};

class B 
{
public:
    std::weak_ptr<A> ptrA; // 使用 weak_ptr 打破循环引用
    ~B() { std::cout << "B destroyed" << std::endl; }
};

int main() 
{
    {
        auto a = std::make_shared<A>();
        auto b = std::make_shared<B>();
        a->ptrB = b;
        b->ptrA = a;
    } // 离开作用域时,a和b的析构函数被调用

    return 0;
}

输出:

A destroyed
B destroyed

在这个例子中,B 类中的 ptrA 被声明为 std::weak_ptr<A>,这意味着它不会增加 A 对象的引用计数。当 main 函数作用域结束时,ab 都能正常被销毁,因为它们的引用计数变为0。

三、具体原因总结

  1. 避免循环引用: std::weak_ptr 的主要作用是防止 std::shared_ptr 之间的循环引用,这会导致内存泄漏。
  2. 轻量级引用: std::weak_ptr 是一种观察者,不会影响对象的生命周期和引用计数。
  3. 安全访问: std::weak_ptr 提供了 expired()lock() 方法,确保在访问对象前验证对象是否仍然存在。

四、如果不用会怎样

如果不使用 std::weak_ptr 而在存在循环引用的场景下使用 std::shared_ptr,会导致以下问题:

  1. 内存泄漏: 对象无法被销毁,造成内存资源无法释放。
  2. 程序崩溃: 在某些情况下,无法释放资源可能会导致程序最终崩溃或出现奇怪的行为。
  3. 调试困难: 循环引用问题通常较难发现和调试,尤其在复杂的对象关系中。

因此,std::weak_ptr 是解决上述问题的一个有效工具,可以确保智能指针管理的对象在适当的时候被正确销毁,从而保证程序的健壮性和资源管理的高效性。

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Warren++

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值