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

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. 如何降低此类场景下的耦合?
  2. 循环引用是否有对应的设计模式解决?事件系统+管理类是否更合适?
  3. 如何优雅实现所有需求?

解决方案

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解决循环引用问题,同时简化管理器的部分逻辑:

  1. Worker持有std::vector<std::weak_ptr<Tool>>,避免持有强引用导致循环;
  2. Tool持有std::weak_ptr<Worker>,同样避免强引用;
  3. 管理器可使用std::unordered_map替代std::map提升性能;
  4. 利用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:22:01