如何为现有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; }
关键说明
- weak_ptr的核心作用:
CookMonitor中的weak_ptr<Recipe>不会增加Recipe的引用计数,因此当所有shared_ptr<Recipe>(比如Burner中的实例)都被释放后,Recipe会被正常销毁。 - 安全访问方式:通过
weak_ptr::lock()方法可以获取一个临时的shared_ptr<Recipe>,如果Recipe已被销毁,lock()会返回空指针,避免访问悬空内存。 - 避免循环引用:如果后续需要让Recipe反向引用Burner(比如Recipe需要知道自己在哪个炉灶上烹饪),可以在Recipe中存储
weak_ptr<Burner>,Burner存储shared_ptr<Recipe>,这样两者不会形成循环引用导致内存泄漏。
内容的提问来源于stack exchange,提问作者James Franco
相关产品推荐
相关产品推荐

