C++11 新特性:再谈 std::weak_ptr 的用法

前面两篇文章已经介绍了 std::weak_ptr,相比之下,std::weak_ptr没有std::shared_ptrstd::shared_ptr好理解,今天通过几个例子看看std::weak_ptr的用法。

std::weak_ptr 的提出主要是用来解决 std::shared_ptr 带来的循环引用问题。

std::shared_ptr 不同,std::weak_ptr 并不拥有对象,也就是说,它的存在不会增加对象的引用计数。这意味着 std::weak_ptr 指向一个对象时,它不会阻止该对象被销毁。std::weak_ptr 适用于跟踪由 std::shared_ptr 管理的对象,而不需要延长该对象的生命周期。

std::weak_ptr 的主要用法包括:

  1. 解决循环引用:当两个对象互相持有对方的 std::shared_ptr 时,会形成循环引用,导致内存泄漏。通过将其中一个对象对另一个对象的引用改为 std::weak_ptr,可以打破循环引用,使得对象能够被正确释放。

  2. 观察者模式:在观察者模式中,观察者(Observer)通常需要跟踪可观察对象(Observable),但不拥有它。使用 std::weak_ptr 可以实现这一点,观察者可以通过 std::weak_ptr 来检查可观察对象是否仍然存在,并在需要时与之交互。

  3. 缓存实现:当实现缓存时,你可能不希望缓存的存在延长对象的生命周期。std::weak_ptr 可以用来跟踪对象,如果对象仍然存在,就可以通过将 std::weak_ptr 提升为 std::shared_ptr 来使用它,否则可以认为对象已经被销毁或需要重新创建。

使用示例

以下是使用 std::weak_ptr 的一些示例代码,展示了上述用法。

解决循环引用

前面已经给出了一个简单的例子。这里不再重复。

观察者模式
#include <iostream>
#include <memory>
#include <vector>

class Observable; // 前向声明

class Observer {
public:
    virtual void update() = 0; // 纯虚函数,供派生类实现
    virtual ~Observer() = default;
};

class Observable {
public:
    void addObserver(const std::weak_ptr<Observer>& observer) {
        observers.push_back(observer);
    }
    
    void notifyObservers() {
        for (auto it = observers.begin(); it != observers.end(); ) {
            if (auto observer = it->lock()) {
                observer->update();
                ++it;
            } else {
                // 如果观察者已经被销毁,从列表中移除
                it = observers.erase(it);
            }
        }
    }
    
private:
    std::vector<std::weak_ptr<Observer>> observers;
};

class ConcreteObserver : public Observer, public std::enable_shared_from_this<ConcreteObserver> {
public:
    void update() override {
        std::cout << "Observer updated.\n";
    }
};

int main() {
    auto observable = std::make_shared<Observable>();
    auto observer1 = std::make_shared<ConcreteObserver>();
    auto observer2 = std::make_shared<ConcreteObserver>();
    
    observable->addObserver(observer1);
    observable->addObserver(observer2);
    
    observable->notifyObservers();
    
    return 0;
}

输出:

Observer updated.
Observer updated.

在这个例子中,Observable 类拥有一个 Observer 对象列表,Observer 通过 std::weak_ptr 被添加到列表中。这样,即使 Observer 对象被销毁,它也不会影响到 Observable 对象的行为。

缓存实现
#include <iostream>
#include <memory>
#include <map>

class Resource;

std::map<int, std::weak_ptr<Resource>> cache;

class Resource {
public:
    Resource(int id) : resourceId(id) {
        std::cout << "Resource " << id << " created.\n";
    }
    
    ~Resource() {
        std::cout << "Resource " << resourceId << " destroyed.\n";
    }
    
    void use() {
        std::cout << "Using resource " << resourceId << ".\n";
    }
    
private:
    int resourceId;
};

std::shared_ptr<Resource> getResource(int id) {
    if (auto found = cache[id].lock()) {
        return found;
    } else {
        auto newResource = std::make_shared<Resource>(id);
        cache[id] = newResource;
        return newResource;
    }
}

int main() {
    auto res1 = getResource(1); // 创建资源
    res1->use(); // 使用资源
    
    res1.reset(); // 显式释放资源
    
    auto res2 = getResource(1); // 由于资源已经释放,这里会创建一个新资源
    
    return 0;
}

输出:

Resource 1 created.
Using resource 1.
Resource 1 destroyed.
Resource 1 created.
Resource 1 destroyed.

在这个缓存实现示例中,当尝试获取一个资源时,会首先检查该资源是否已存在于缓存中。

如果 std::weak_ptr 能够被提升为 std::shared_ptr,说明资源仍然存在;否则,会创建一个新的资源并将其加入到缓存中。

这样做既避免了不必要的资源重复创建,又确保了资源可以在不再被需要时正确地被销毁。

总结

std::weak_ptr 提供了一种机制,来观察和跟踪 std::shared_ptr 所管理的对象,而不延长其生命周期。这在解决循环引用、实现观察者模式、以及在特定场景下管理缓存时非常有用。

通过 std::weak_ptr,开发者可以更灵活地管理内存,避免潜在的内存泄漏问题。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值