有了 unique_ptr 和 shared_ptr,要weak_ptr 有什么用?

说明

weak_ptr是C++中智能指针的一种,与shared_ptr配合使用,weak_ptr不对对象的生命周期进行管理,即它持有对象的引用但不增加对象的引用计数。这意味着weak_ptr的存在不会阻止其所指向的对象被销毁。

使用场景

防止循环引用

当两个对象互相持有对方的shared_ptr时,会导致引用计数永远不为零,从而引起内存泄漏。在这种情况下,可将其中一个对象持有对方的weak_ptr来解决循环引用问题。

代码演示:

#include <memory>
#include <iostream>

class B; // 前向声明

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

class B {
public:
    // 使用weak_ptr替代shared_ptr解决循环引用
    std::weak_ptr<A> a_ptr; 
    ~B() { std::cout << "B destroyed" << std::endl; }
};

int main() {
    auto a = std::make_shared<A>();
    auto b = std::make_shared<B>();

    a->b_ptr = b;
    b->a_ptr = a; // 不增加引用计数

    // 此时,尽管A和B互相引用,但由于使用了weak_ptr,对象能够被正确销毁。
    return 0;
}

这个例子中,即使A和B互相引用,当它们离开作用域时,都能被正确地销毁。这是因为B持有的是一个指向A的weak_ptr,不会增加A的引用计数。

临时访问共享资源

当你需要临时访问由shared_ptr管理的资源,但又不想拥有资源所有权时。通过weak_ptr,你可以在资源存在时访问它,而不会干扰资源的生命周期管理。

代码演示;

#include <iostream>
#include <memory>

class Resource {
public:
    Resource() { std::cout << "Resource Acquired\n"; }
    ~Resource() { std::cout << "Resource Released\n"; }
    void do_something() { std::cout << "Doing something\n"; }
};

int main() {
    std::weak_ptr<Resource> weakResource;

    {
        auto sharedResource = std::make_shared<Resource>(); // 在这个作用域中创建资源
        weakResource = sharedResource; // 把 shared_ptr 赋给 weak_ptr,用于监测资源
        
        // 检查资源是否存在
        if (auto tempShared = weakResource.lock()) { // 尝试将 weak_ptr 提升为 shared_ptr
            tempShared->do_something(); // 资源存在,使用资源
        } else {
            std::cout << "Resource is no longer available\n";
        }
    } // 资源在这个作用域结束时被释放

    // 再次检查资源是否存在
    if (auto tempShared = weakResource.lock()) { // 尝试将 weak_ptr 提升为 shared_ptr
        tempShared->do_something(); // 如果资源仍然存在,使用资源
    } else {
        std::cout << "Resource is no longer available\n"; // 资源已经被释放
    }

    return 0;
}

在这个例子中,Resource类代表一个需要被监测状态的资源。我们首先创建了一个类型为Resource的shared_ptr,并将其与一个weak_ptr相关联。weak_ptr不会增加资源的引用计数,因此不会影响资源的生命周期。

在第一个作用域内,我们通过weak_ptr的lock()方法尝试提升它为shared_ptr,以访问资源。因为资源此时仍然存在,所以提升操作成功,我们可以通过返回的shared_ptr安全地使用资源。

一旦第一个作用域结束,shared_ptr会被销毁,从而释放资源。此时,如果我们再次尝试通过weak_ptr提升来访问资源,操作将失败,因为资源已经不再存在。此时lock()方法会返回一个空的shared_ptr,这允许我们检测到资源已经被释放。

通过这种方式,weak_ptr可以被用作一种有效的机制,以监测和检查由shared_ptr管理的资源的状态。

03-24 12:30