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

如何为现有C++智能指针食谱示例添加weak_ptr使用场景?

在食谱场景中使用weak_ptr的具体场景与实现方案

适用场景:烹饪进度监控器

假设我们需要一个CookMonitor(烹饪进度监控器),它的职责是跟踪食谱的烹饪状态,但不需要拥有食谱的所有权——也就是说,当所有炉灶(Burner)都不再使用某个食谱时,这个食谱应该被正常销毁,监控器不应该阻止这一过程。如果用shared_ptr,监控器会增加食谱的引用计数,导致即使炉灶都用完了,食谱也无法被释放;而weak_ptr刚好满足这种"只访问、不持有所有权"的需求。

另外,若需要实现食材反向关联食谱的功能(比如某个食材想知道自己属于哪个食谱),也可以用weak_ptr:Recipe用unique_ptr持有Ingredient,Ingredient用weak_ptr<Recipe>关联所属食谱,避免形成Recipe <-> Ingredient的循环引用导致内存泄漏。

下面以CookMonitor为例给出实现方案:

完整代码实现

#include <vector>
#include <memory>
#include <iostream>
#include <algorithm>

// 食材类
class Ingredient {
public:
    std::string name;
    Ingredient(std::string n) : name(std::move(n)) {}
};

// 食谱类:用unique_ptr独占食材所有权
class Recipe {
public:
    std::string name;
    std::vector<std::unique_ptr<Ingredient>> ingredients;

    Recipe(std::string n) : name(std::move(n)) {}

    void addIngredient(std::unique_ptr<Ingredient> i) {
        ingredients.push_back(std::move(i));
    }

    // 模拟烹饪状态
    bool isCooking() const {
        return !ingredients.empty(); // 简化逻辑:有食材则正在烹饪
    }
};

// 炉灶类:用shared_ptr共享食谱所有权
class Burner {
public:
    std::vector<std::shared_ptr<Recipe>> recipes;

    void addRecipe(const std::shared_ptr<Recipe>& r) {
        recipes.emplace_back(r);
    }

    // 模拟移除食谱(比如烹饪完成)
    void removeRecipe(const std::shared_ptr<Recipe>& r) {
        auto it = std::find(recipes.begin(), recipes.end(), r);
        if (it != recipes.end()) {
            recipes.erase(it);
        }
    }
};

// 烹饪监控器:用weak_ptr无所有权访问食谱
class CookMonitor {
private:
    std::vector<std::weak_ptr<Recipe>> trackedRecipes;

public:
    // 添加要监控的食谱
    void trackRecipe(const std::weak_ptr<Recipe>& r) {
        trackedRecipes.push_back(r);
    }

    // 检查所有被监控食谱的状态
    void checkAllStatus() {
        std::cout << "=== 烹饪状态检查 ===" << std::endl;
        // 遍历并清理已失效的weak_ptr
        for (auto it = trackedRecipes.begin(); it != trackedRecipes.end();) {
            if (auto recipePtr = it->lock()) { // lock()获取shared_ptr,若已失效则返回空
                std::cout << "食谱《" << recipePtr->name << "》状态:" 
                          << (recipePtr->isCooking() ? "正在烹饪" : "已完成") << std::endl;
                ++it;
            } else {
                // 食谱已被销毁,移除监控记录
                std::cout << "发现已销毁的食谱,移除监控" << std::endl;
                it = trackedRecipes.erase(it);
            }
        }
        std::cout << "====================" << std::endl;
    }
};

// 演示代码
int main() {
    auto tomatoSoup = std::make_shared<Recipe>("番茄汤");
    tomatoSoup->addIngredient(std::make_unique<Ingredient>("番茄"));
    tomatoSoup->addIngredient(std::make_unique<Ingredient>("鸡蛋"));

    Burner kitchenBurner;
    kitchenBurner.addRecipe(tomatoSoup);

    CookMonitor monitor;
    monitor.trackRecipe(tomatoSoup);

    // 第一次检查状态
    monitor.checkAllStatus();

    // 炉灶移除食谱(烹饪完成)
    kitchenBurner.removeRecipe(tomatoSoup);
    // 手动释放最后一个shared_ptr
    tomatoSoup.reset();

    // 第二次检查状态:食谱已被销毁
    monitor.checkAllStatus();

    return 0;
}

关键说明

  1. weak_ptr的核心作用:CookMonitor中的weak_ptr<Recipe>不会增加Recipe的引用计数,因此当所有shared_ptr<Recipe>(比如Burner中的实例)都被释放后,Recipe会被正常销毁。
  2. 安全访问方式:通过weak_ptr::lock()方法可以获取一个临时的shared_ptr<Recipe>,如果Recipe已被销毁,lock()会返回空指针,避免访问悬空内存。
  3. 避免循环引用:如果后续需要让Recipe反向引用Burner(比如Recipe需要知道自己在哪个炉灶上烹饪),可以在Recipe中存储weak_ptr<Burner>,Burner存储shared_ptr<Recipe>,这样两者不会形成循环引用导致内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 09:44:54