【智能指针】std::weak_ptr

std::weak_ptr 是 C++ 中与 std::shared_ptr 配套使用的智能指针,用于观察共享资源而不影响其生命周期。以下是其核心特性、使用场景及详细示例:


1. 核心特性

特性说明
不持有所有权不增加引用计数,仅作为观察者存在
依赖 shared_ptr必须通过 shared_ptr 构造,不能直接管理资源
安全访问资源通过 lock() 返回临时 shared_ptr,避免访问已释放资源
解决循环引用打破 shared_ptr 的循环依赖,防止内存泄漏

2. 基础用法

构造与初始化
auto shared = std::make_shared<int>(42);
std::weak_ptr<int> weak(shared);  // 通过 shared_ptr 构造 weak_ptr
安全访问资源
if (auto temp_shared = weak.lock()) { // 尝试提升为 shared_ptr
    std::cout << *temp_shared;        // 资源存在时安全访问
} else {
    std::cout << "资源已释放";
}
检查有效性
// 方法 1:检查提升后的 shared_ptr 是否为空
bool valid = !weak.expired();  // 不保证准确性(可能瞬间失效)

// 方法 2(推荐):直接尝试 lock()
if (auto sp = weak.lock()) {
    // 操作 sp
}

3. 典型应用场景

场景 1:打破循环引用
// 错误示例:父节点和子节点互相持有 shared_ptr
class Node {
public:
    std::shared_ptr<Node> child; // 导致循环引用,无法释放
    // 修正方案:
    std::weak_ptr<Node> parent; // 使用 weak_ptr 断开循环
};
场景 2:缓存临时访问
class Cache {
    std::unordered_map<int, std::weak_ptr<Resource>> cache;

public:
    std::shared_ptr<Resource> get(int key) {
        auto it = cache.find(key);
        if (it != cache.end()) {
            return it->second.lock(); // 资源存在则复用,否则新建
        }
        auto new_res = std::make_shared<Resource>(key);
        cache[key] = new_res; // 存储 weak_ptr
        return new_res;
    }
};
场景 3:观察者模式
class Subject {
    std::vector<std::weak_ptr<Observer>> observers;

public:
    void notify() {
        for (auto& weak_obs : observers) {
            if (auto obs = weak_obs.lock()) {
                obs->update(); // 仅通知存活的观察者
            }
        }
    }
};

4. 底层原理

控制块结构
+-------------------+  
|    Control Block  |  
| +---------------+ |  
| | 强引用计数    | |  
| | (shared_ptr)  | |  
| +---------------+ |  
| +---------------+ |  
| | 弱引用计数    | |  
| | (weak_ptr)    | |  
| +---------------+ |  
+-------------------+  
        |  
        v  
      Object
  • 强引用计数归零时:销毁对象
  • 弱引用计数归零时:释放控制块

5. 性能与线程安全

操作性能影响线程安全保证
构造/析构无原子操作,低成本无竞争条件下安全
lock()涉及原子操作,中等开销线程安全(返回的 shared_ptr 需用户同步)
expired()快速检查,但结果可能瞬间失效需外部同步保证准确性

6. 常见错误与规避

错误 1:直接访问 weak_ptr 管理的资源
std::weak_ptr<Widget> weak = ...;
weak->do_something();  // 错误!weak_ptr 没有重载 -> 和 * 操作符

修正:必须通过 lock() 获取临时 shared_ptr 后访问。

错误 2:长期持有 weak_ptr
void process(std::weak_ptr<Data> weak_data) {
    // 长时间运行后...
    if (auto data = weak_data.lock()) { // 可能已失效
        data->process(); 
    }
}

修正:尽早 lock() 并持有返回的 shared_ptr

错误 3:误用 expired() 作为同步检查
if (!weak.expired()) {          // 不安全:检查后可能立即失效
    auto sp = weak.lock();      // sp 可能为空
    if (sp) sp->operate();
}

修正:原子化检查与提升操作:

if (auto sp = weak.lock()) {    // 原子操作
    sp->operate();
}

7. 最佳实践

  1. 始终通过 lock() 访问资源

    • 避免使用 expired() 单独判断有效性。
    • 对返回的 shared_ptr 判空后再操作。
  2. 优先使用 make_shared

    auto shared = std::make_shared<Object>();  // 合并对象和控制块内存
    std::weak_ptr<Object> weak(shared); 
    • 避免裸指针初始化导致的分离内存分配。
  3. 避免跨线程传递 weak_ptr 的时效性假设

    • 即使 lock() 成功,资源可能在后续代码中失效,需设计重试机制。
  4. 限制生命周期

    {
        auto shared = std::make_shared<Resource>();
        std::weak_ptr<Resource> weak(shared);
        // 确保 shared 存活期间使用 weak
    } // shared 析构后,weak 自动失效

示例:弱引用工厂

class ObjectFactory {
    static std::vector<std::weak_ptr<Object>> instances;

public:
    static std::shared_ptr<Object> create() {
        auto obj = std::make_shared<Object>();
        instances.emplace_back(obj);
        return obj;
    }

    static void cleanup() {
        // 清除所有已释放的弱引用
        auto it = std::remove_if(instances.begin(), instances.end(),
            [](const auto& weak) { return weak.expired(); });
        instances.erase(it, instances.end());
    }
};

总结

std::weak_ptr 是 shared_ptr 生态的重要补充,核心价值在于:

  • 安全观察共享资源,不干预生命周期
  • 解决循环引用导致的内存泄漏
  • 实现缓存、观察者等模式

使用时需严格遵循 lock() 流程,避免直接操作资源指针,同时注意多线程环境下的状态一致性。正确应用可显著提升代码的健壮性和资源管理效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浩瀚之水_csdn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值