C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ weak_ptr

C++中智能指针weak_ptr的原理及使用

作者:北辰alk

weak_ptr是C++11引入的一种智能指针,本文主要介绍了C++中智能指针weak_ptr的原理及使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. weak_ptr 的基本概念

weak_ptr 是 C++11 引入的一种智能指针,它与 shared_ptr 配合使用,主要解决以下问题:

2. weak_ptr 的核心原理

2.1 控制块结构

weak_ptr 与 shared_ptr 共享同一个控制块,控制块包含:

struct ControlBlock {
    std::atomic<size_t> shared_count;  // 强引用计数
    std::atomic<size_t> weak_count;    // 弱引用计数
    // 其他元数据(删除器、分配器等)
};

2.2 内存管理规则

2.3 工作流程

// 创建 shared_ptr(控制块:shared=1, weak=0)
auto sp = std::make_shared<int>(42);

// 创建 weak_ptr(控制块:shared=1, weak=1)
std::weak_ptr<int> wp = sp;

// shared_ptr 析构(控制块:shared=0, weak=1)
sp.reset();

// 此时:
// - 管理的 int 对象已被销毁
// - 控制块仍然存在(weak_count=1)
// - wp.expired() == true

// weak_ptr 析构(控制块:shared=0, weak=0)
// 控制块被释放

3. weak_ptr 的关键操作

3.1 创建与赋值

// 从 shared_ptr 创建
auto sp = std::make_shared<MyClass>();
std::weak_ptr<MyClass> wp1(sp);

// 拷贝构造
std::weak_ptr<MyClass> wp2(wp1);

// 赋值操作
std::weak_ptr<MyClass> wp3;
wp3 = wp1;

3.2 检查与升级

// 检查对象是否有效
if (!wp.expired()) {
    // 尝试升级为 shared_ptr
    if (auto sp = wp.lock()) {
        // 使用 sp 安全访问对象
    }
}

3.3 资源释放监控

// 监控资源释放
std::weak_ptr<MyClass> wp;

{
    auto sp = std::make_shared<MyClass>();
    wp = sp;
    // 对象存在
}

// 此时 wp.expired() == true

4. weak_ptr 的线程安全性

4.1 官方标准规定

4.2 线程安全示例

std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp(sp);

// 线程1
if (auto local_sp = wp.lock()) {
    std::lock_guard<std::mutex> lock(mtx);
    *local_sp = 10;
}

// 线程2
if (auto local_sp = wp.lock()) {
    std::lock_guard<std::mutex> lock(mtx);
    int val = *local_sp;
}

5. weak_ptr 的典型应用场景

5.1 打破循环引用

class Parent {
    std::shared_ptr<Child> child;
};

class Child {
    std::weak_ptr<Parent> parent;  // 使用 weak_ptr 避免循环
};

5.2 缓存系统

class Cache {
    std::unordered_map<Key, std::weak_ptr<Resource>> cache;
    
    std::shared_ptr<Resource> get(Key key) {
        if (auto it = cache.find(key); it != cache.end()) {
            if (auto sp = it->second.lock()) {
                return sp;  // 缓存命中
            }
            cache.erase(it);  // 清理过期缓存
        }
        // 缓存未命中,创建新资源
        auto sp = std::make_shared<Resource>(key);
        cache[key] = sp;
        return sp;
    }
};

5.3 观察者模式

class Subject {
    std::vector<std::weak_ptr<Observer>> observers;
    
    void notify() {
        for (auto it = observers.begin(); it != observers.end(); ) {
            if (auto obs = it->lock()) {
                obs->update();
                ++it;
            } else {
                it = observers.erase(it);  // 移除无效观察者
            }
        }
    }
};

6. weak_ptr 的实现细节

6.1 控制块生命周期

6.2 lock() 的原子实现

lock() 操作必须保证线程安全,伪代码实现:

shared_ptr<T> lock() const noexcept {
    ControlBlock* cb = get_control_block();
    size_t sc = cb->shared_count.load();
    do {
        if (sc == 0) return nullptr;  // 对象已释放
        // 尝试增加 shared_count(CAS操作)
    } while (!cb->shared_count.compare_exchange_weak(sc, sc + 1));
    
    return shared_ptr<T>(cb);  // 创建新的 shared_ptr
}

7. weak_ptr 的注意事项

不能直接解引用:必须先用 lock() 升级为 shared_ptr

// 错误用法
// *wp;  // 编译错误

// 正确用法
if (auto sp = wp.lock()) {
    *sp = value;
}

性能考虑

构造函数限制

// 不能直接从裸指针构造
// std::weak_ptr<int> wp(new int(42));  // 错误

// 必须从 shared_ptr 构造
auto sp = std::make_shared<int>(42);
std::weak_ptr<int> wp(sp);  // 正确

8. 性能优化建议

避免频繁 lock/unlock:在需要时缓存 shared_ptr

void process(std::weak_ptr<Data> wp) {
    auto sp = wp.lock();  // 只调用一次 lock
    if (!sp) return;
    
    // 多次使用 sp 而不重复调用 lock
    sp->operation1();
    sp->operation2();
}

及时清理失效 weak_ptr:定期检查并移除 expired() 的 weak_ptr

考虑使用 make_shared:对象和控制块单次分配,减少内存碎片

9. 与其它智能指针的对比

特性weak_ptrshared_ptrunique_ptr
所有权共享独占
影响生命周期
直接访问对象需通过 lock()可直接访问可直接访问
引用计数只增加 weak_count增加 shared_count
典型用途打破循环引用/观察共享所有权独占所有权

10. 现代 C++ 中的增强

10.1 C++17 的 weak_from_this

class MyClass : public std::enable_shared_from_this<MyClass> {
public:
    std::weak_ptr<MyClass> get_weak() {
        return weak_from_this();  // 安全获取 weak_ptr
    }
};

auto obj = std::make_shared<MyClass>();
auto wobj = obj->get_weak();  // 安全获取 weak_ptr

10.2 C++20 的原子 shared_ptr/weak_ptr

std::atomic<std::weak_ptr<int>> atomic_wp;
atomic_wp.store(wp, std::memory_order_release);
auto current = atomic_wp.load(std::memory_order_acquire);

11. 总结

weak_ptr 的核心原理可以总结为:

正确使用 weak_ptr 可以:

理解 weak_ptr 的工作原理对于设计复杂的内存管理系统和避免资源泄漏至关重要,它是现代 C++ 高效内存管理工具链中不可或缺的一环。

到此这篇关于C++中智能指针weak_ptr的原理及使用的文章就介绍到这了,更多相关C++ weak_ptr内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文