C++98中一对多+多对多关联的循环引用处理方案咨询
C++98下Worker/Tool/Workshop关联管理的优雅实现
问题背景
需基于C++98标准实现Worker类,该类可持有抽象Tool对象。Tool可独立存在,能被工人装备或卸下,且同一工具只能归属一名工人。对象生命周期需满足:
- 若
Tool被销毁,需自动从工人处卸下,避免悬空指针; - 若
Worker被销毁,需解除其对所有Tool的归属; - 已归属某工人的
Tool分配给另一工人时,需先从原工人处移除。
此外,Workshop为Tool子类型的模板类,仅接受拥有指定类型可用工具的工人:
- 工人加入车间时,随机关联对应类型的可用工具,该工具无法被其他工人用于加入车间;
Worker销毁时自动退出车间;- 工人在车间使用的
Tool被销毁或分配给他人时,工人自动退出车间。
当前困境
Worker与Tool互相持有指针,Tool::unset_owner()和Worker::unequip(Tool*)互相调用引发无限循环;- 为支持
Workshop,引入WorkshopBase并在Worker中维护std::map<Tool*, WorkshopBase*>,进一步加剧链式调用与耦合度。
核心问题
- 如何降低此类场景下的耦合?
- 循环引用是否有对应的设计模式解决?事件系统+管理类是否更合适?
- 如何优雅实现所有需求?
解决方案
1. 降低耦合的核心思路
引入中介者模式,用单例的AssociationManager统一管理所有Worker、Tool、Workshop之间的关联关系,将原本分散在各个类中的关联逻辑(装备/卸装、加入/退出车间)全部转移到管理器中。这样:
Worker、Tool、Workshop无需直接持有对方的指针,仅通过管理器完成关联操作;- 所有关联变更的触发逻辑(如销毁、分配)都通过管理器转发,避免类之间的直接调用,彻底降低耦合。
2. 解决循环引用的方案
循环引用的根源是双向直接调用,通过以下两点彻底解决:
- 用管理器作为中间层,
Tool销毁时仅通知管理器,由管理器去处理Worker的卸装逻辑,反之亦然,消除双向直接调用; - 若出于性能考虑必须保留双向指针,则在关联变更方法中添加递归保护标志,进入方法时设置标志,执行完恢复,避免互相调用触发无限循环。
事件系统+管理类是非常合适的方案:管理器作为事件调度中心,各个对象仅负责触发事件(如Tool销毁时触发ToolDestroyed事件),管理器监听事件并执行对应的关联清理逻辑。
3. C++98完整实现示例
第一步:定义基础类与管理器接口
#include <vector> #include <map> #include <set> #include <stdexcept> // 前置声明 class Worker; class Tool; class WorkshopBase; // 关联管理器,单例模式(C++98实现) class AssociationManager { private: AssociationManager() {} AssociationManager(const AssociationManager&); AssociationManager& operator=(const AssociationManager&); // 存储Worker -> 所持有的Tools std::map<Worker*, std::set<Tool*>> worker_to_tools; // 存储Tool -> 所属的Worker std::map<Tool*, Worker*> tool_to_worker; // 存储Tool -> 绑定的Workshop std::map<Tool*, WorkshopBase*> tool_to_workshop; // 存储Worker -> 所在的Workshops std::map<Worker*, std::set<WorkshopBase*>> worker_to_workshops; public: static AssociationManager& getInstance() { static AssociationManager instance; return instance; } // Worker关联Tool的方法 void assignToolToWorker(Tool* tool, Worker* worker); void removeToolFromWorker(Tool* tool, Worker* worker); // Workshop关联的方法 void bindToolToWorkshop(Tool* tool, WorkshopBase* workshop); void unbindToolFromWorkshop(Tool* tool); // 销毁通知方法 void onWorkerDestroyed(Worker* worker); void onToolDestroyed(Tool* tool); }; // 抽象Tool类 class Tool { public: virtual ~Tool() { // 通知管理器自身销毁 AssociationManager::getInstance().onToolDestroyed(this); } // 禁止直接设置owner,统一通过管理器 void setOwner(Worker* worker) { AssociationManager::getInstance().assignToolToWorker(this, worker); } Worker* getOwner() const { std::map<Tool*, Worker*>::const_iterator it = AssociationManager::getInstance().tool_to_worker.find(const_cast<Tool*>(this)); return it != AssociationManager::getInstance().tool_to_worker.end() ? it->second : NULL; } }; // Worker类 class Worker { public: ~Worker() { // 通知管理器自身销毁 AssociationManager::getInstance().onWorkerDestroyed(this); } void equip(Tool* tool) { tool->setOwner(this); } void unequip(Tool* tool) { AssociationManager::getInstance().removeToolFromWorker(tool, this); } const std::set<Tool*>& getTools() const { static std::set<Tool*> empty_set; std::map<Worker*, std::set<Tool*>>::const_iterator it = AssociationManager::getInstance().worker_to_tools.find(const_cast<Worker*>(this)); return it != AssociationManager::getInstance().worker_to_tools.end() ? it->second : empty_set; } }; // Workshop基类,隐藏模板参数 class WorkshopBase { public: virtual ~WorkshopBase() { // 清理所有绑定的工具和工人 std::map<Tool*, WorkshopBase*>& tool_map = AssociationManager::getInstance().tool_to_workshop; std::vector<Tool*> to_unbind; for (std::map<Tool*, WorkshopBase*>::iterator it = tool_map.begin(); it != tool_map.end(); ++it) { if (it->second == this) { to_unbind.push_back(it->first); } } for (size_t i = 0; i < to_unbind.size(); ++i) { AssociationManager::getInstance().unbindToolFromWorkshop(to_unbind[i]); } } virtual void removeWorker(Worker* worker) = 0; }; // 模板Workshop类 template <typename ToolType> class Workshop : public WorkshopBase { private: std::set<Worker*> workers; std::set<ToolType*> availableTools; // 可用的工具池 public: void addWorker(Worker* worker) { if (availableTools.empty()) { throw std::runtime_error("No available tools for this workshop"); } ToolType* tool = *availableTools.begin(); availableTools.erase(availableTools.begin()); // 关联工具、工人、车间 AssociationManager::getInstance().assignToolToWorker(tool, worker); AssociationManager::getInstance().bindToolToWorkshop(tool, this); workers.insert(worker); } void removeWorker(Worker* worker) { workers.erase(worker); // 回收工具到可用池 const std::set<Tool*>& workerTools = worker->getTools(); for (std::set<Tool*>::const_iterator it = workerTools.begin(); it != workerTools.end(); ++it) { WorkshopBase* ws = AssociationManager::getInstance().tool_to_workshop.find(*it)->second; if (ws == this) { availableTools.insert(static_cast<ToolType*>(*it)); AssociationManager::getInstance().unbindToolFromWorkshop(*it); break; } } } // 添加可用工具到车间 void addAvailableTool(ToolType* tool) { availableTools.insert(tool); } };
第二步:实现管理器的核心逻辑
// 实现AssociationManager的方法 void AssociationManager::assignToolToWorker(Tool* tool, Worker* worker) { // 如果工具已有归属,先移除 std::map<Tool*, Worker*>::iterator toolIt = tool_to_worker.find(tool); if (toolIt != tool_to_worker.end()) { removeToolFromWorker(tool, toolIt->second); } // 建立新关联 tool_to_worker[tool] = worker; worker_to_tools[worker].insert(tool); } void AssociationManager::removeToolFromWorker(Tool* tool, Worker* worker) { // 移除Worker->Tool的关联 std::map<Worker*, std::set<Tool*>>::iterator workerIt = worker_to_tools.find(worker); if (workerIt != worker_to_tools.end()) { workerIt->second.erase(tool); if (workerIt->second.empty()) { worker_to_tools.erase(workerIt); } } // 移除Tool->Worker的关联 std::map<Tool*, Worker*>::iterator toolIt = tool_to_worker.find(tool); if (toolIt != tool_to_worker.end()) { tool_to_worker.erase(toolIt); } // 如果该工具绑定了Workshop,通知Workshop移除工人 std::map<Tool*, WorkshopBase*>::iterator wsIt = tool_to_workshop.find(tool); if (wsIt != tool_to_workshop.end()) { wsIt->second->removeWorker(worker); unbindToolFromWorkshop(tool); } } void AssociationManager::bindToolToWorkshop(Tool* tool, WorkshopBase* workshop) { tool_to_workshop[tool] = workshop; worker_to_workshops[tool_to_worker[tool]].insert(workshop); } void AssociationManager::unbindToolFromWorkshop(Tool* tool) { std::map<Tool*, WorkshopBase*>::iterator wsIt = tool_to_workshop.find(tool); if (wsIt != tool_to_workshop.end()) { Worker* worker = tool_to_worker[tool]; worker_to_workshops[worker].erase(wsIt->second); if (worker_to_workshops[worker].empty()) { worker_to_workshops.erase(worker); } tool_to_workshop.erase(wsIt); } } void AssociationManager::onWorkerDestroyed(Worker* worker) { // 移除该工人所有工具的关联 std::map<Worker*, std::set<Tool*>>::iterator workerIt = worker_to_tools.find(worker); if (workerIt != worker_to_tools.end()) { std::set<Tool*> tools = workerIt->second; for (std::set<Tool*>::iterator it = tools.begin(); it != tools.end(); ++it) { removeToolFromWorker(*it, worker); } worker_to_tools.erase(workerIt); } // 移除该工人所在的所有车间 std::map<Worker*, std::set<WorkshopBase*>>::iterator wsIt = worker_to_workshops.find(worker); if (wsIt != worker_to_workshops.end()) { std::set<WorkshopBase*> workshops = wsIt->second; for (std::set<WorkshopBase*>::iterator it = workshops.begin(); it != workshops.end(); ++it) { (*it)->removeWorker(worker); } worker_to_workshops.erase(wsIt); } } void AssociationManager::onToolDestroyed(Tool* tool) { // 移除工具与工人的关联 std::map<Tool*, Worker*>::iterator toolIt = tool_to_worker.find(tool); if (toolIt != tool_to_worker.end()) { removeToolFromWorker(tool, toolIt->second); } // 移除工具与车间的关联 unbindToolFromWorkshop(tool); }
脚注:C++11及以上版本的优化实现
在新标准中,可使用智能指针替代裸指针,结合std::weak_ptr解决循环引用问题,同时简化管理器的部分逻辑:
Worker持有std::vector<std::weak_ptr<Tool>>,避免持有强引用导致循环;Tool持有std::weak_ptr<Worker>,同样避免强引用;- 管理器可使用
std::unordered_map替代std::map提升性能; - 利用
std::shared_ptr的析构特性,自动触发关联清理逻辑,无需手动调用onDestroyed方法。
示例片段:
#include <memory> #include <unordered_map> #include <algorithm> class Tool : public std::enable_shared_from_this<Tool> { private: std::weak_ptr<Worker> owner_; public: void setOwner(std::shared_ptr<Worker> worker) { if (auto oldOwner = owner_.lock()) { oldOwner->unequip(shared_from_this()); } owner_ = worker; worker->equip(shared_from_this()); } }; class Worker : public std::enable_shared_from_this<Worker> { private: std::vector<std::weak_ptr<Tool>> tools_; public: void equip(std::shared_ptr<Tool> tool) { tools_.push_back(tool); } void unequip(std::shared_ptr<Tool> tool) { // 移除对应的weak_ptr tools_.erase(std::remove_if(tools_.begin(), tools_.end(), [&tool](const std::weak_ptr<Tool>& wp) { auto locked = wp.lock(); return locked && locked == tool; }), tools_.end()); } };
内容的提问来源于stack exchange,提问作者Mampac
相关产品推荐
相关产品推荐

