You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++并发设计模式:资源按需创建与自动销毁问题

解决方案:线程安全的按需共享资源管理

你的核心问题在于Room类的std::shared_ptr<R> resource成员持有了一个额外的强引用,导致即使外部所有shared_ptr都释放了,引用计数仍不为0,资源要等到Room对象销毁才会被回收。我们可以通过std::weak_ptr来解决这个问题——它不会持有强引用,仅作为资源的观察者,这样只有外部返回的shared_ptr才参与引用计数。

修正后的代码

#include <iostream>
#include <memory>
#include <mutex>

struct Lights {
    Lights(){ std::cout << "LIGHTS TURNED ON\n"; }
    ~Lights(){ std::cout << "Deleter called.\nLIGHTS TURNED OFF\n\n"; }
};

template <class R>
class Room {
public:
    std::shared_ptr<R> Enter() {
        std::lock_guard<std::mutex> lock(resourceMutex);
        // 尝试从weak_ptr获取强引用
        auto sp = resource.lock();
        if (!sp) {
            // 资源已销毁或未创建,创建新实例
            sp = std::make_shared<R>();
            resource = sp;
        } else {
            std::cout << "  ...lights already on\n";
        }
        return sp;
    }

private:
    std::mutex resourceMutex;
    // 使用weak_ptr替代shared_ptr,不持有强引用
    std::weak_ptr<R> resource;
};

int main() {
    Room<Lights> room;
    auto sp1 = room.Enter();
    auto sp2 = room.Enter();
    auto sp3 = room.Enter();
    sp1.reset();
    sp2.reset();
    sp3.reset();

    std::cout << "END of program.\n";
    return 0;
}

关键改动说明

  1. 替换std::shared_ptr为std::weak_ptr:Room类的resource成员改为std::weak_ptr<R>,它不会增加资源的引用计数,仅用于观察资源是否存在。
  2. 通过lock()获取强引用:每次调用Enter()时,先调用resource.lock()尝试获取有效的std::shared_ptr。如果返回空,说明资源已销毁或从未创建,此时才创建新资源。
  3. 简化销毁逻辑:把原自定义删除器的提示信息移到Lights的析构函数中,依赖std::shared_ptr默认的RAII销毁机制,最后一个强引用释放时自动触发资源销毁。

输出验证

运行修正后的代码,输出将完全符合你的期望:

LIGHTS TURNED ON
  ...lights already on
  ...lights already on
Deleter called.
LIGHTS TURNED OFF

END of program.

线程安全与特性保障

  • 单实例与线程安全:std::mutex保护了资源的创建和weak_ptr的访问过程,避免多个线程同时创建资源,保证单实例特性。
  • 自动销毁:只有外部返回的shared_ptr持有强引用,最后一个引用释放时资源立即销毁,无需等待Room对象生命周期结束。
  • 可复用性:资源销毁后,weak_ptr自动失效,下次调用Enter()会重新创建资源,满足"关闭后可再次打开"的需求,这是std::call_once无法实现的。

内容的提问来源于stack exchange,提问作者NKatUT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 16:06:28