gpt4 book ai didi

c++ - 将现有的类结构移植到智能指针

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:04:38 26 4
gpt4 key购买 nike

我知道这个问题很长,但我不确定如何用更短的方式解释我的问题。问题本身是关于类层次结构的设计,尤其是如何将基于指针的现有层次结构移植到使用智能指针的层次结构中。如果有人能想出一些方法来简化我的解释,从而使这个问题更通用,请告诉我。这样,它可能对更多 SO 读者有用。

我正在设计一个 C++ 应用程序来处理一个允许我读取一些传感器的系统。该系统由我收集测量值的远程机器组成。此应用程序实际上必须使用两个不同的子系统:

  • 聚合系统:这种类型的系统包含我收集测量值的几个组件。所有通信都通过聚合系统,如果需要,聚合系统会将数据重定向到特定组件(发送到聚合系统本身的全局命令不需要传输到单个组件)。
  • 独立系统:在这种情况下,只有一个系统,所有通信(包括全局命令)都发送到该系统。

  • 接下来你可以看到我想出的类图:

    class diagram

    独立系统继承了 ConnMgrMeasurementDevice .另一方面,聚合系统在 AggrSystem 之间拆分其功能。和 Component .

    基本上,作为用户,我想要的是 MeasurementDevice对象并将数据透明地发送到相应的端点,无论是聚合系统还是独立系统。

    当前实现

    这是我目前的实现。首先,两个基础抽象类:
    class MeasurementDevice {
    public:
    virtual ~MeasurementDevice() {}
    virtual void send_data(const std::vector<char>& data) = 0;
    };

    class ConnMgr {
    public:
    ConnMgr(const std::string& addr) : addr_(addr) {}
    virtual ~ConnMgr() {}
    virtual void connect() = 0;
    virtual void disconnect() = 0;

    protected:
    std::string addr_;
    };

    这些是聚合系统的类:
    class Component : public MeasurementDevice {
    public:
    Component(AggrSystem& as, int slot) : aggr_sys_(as), slot_(slot) {}
    void send_data(const std::vector<char>& data) {
    aggr_sys_.send_data(slot_, data);
    }
    private:
    AggrSystem& aggr_sys_;
    int slot_;
    };

    class AggrSystem : public ConnMgr {
    public:
    AggrSystem(const std::string& addr) : ConnMgr(addr) {}
    ~AggrSystem() { for (auto& entry : components_) delete entry.second; }

    // overridden virtual functions omitted (not using smart pointers)

    MeasurementDevice* get_measurement_device(int slot) {
    if (!is_slot_used(slot)) throw std::runtime_error("Empty slot");
    return components_.find(slot)->second;
    }
    private:
    std::map<int, Component*> components_;

    bool is_slot_used(int slot) const {
    return components_.find(slot) != components_.end();
    }
    void add_component(int slot) {
    if (is_slot_used(slot)) throw std::runtime_error("Slot already used");
    components_.insert(std::make_pair(slot, new Component(*this, slot)));
    }
    };

    这是独立系统的代码:
    class StandAloneSystem : public ConnMgr, public MeasurementDevice {
    public:
    StandAloneSystem(const std::string& addr) : ConnMgr(addr) {}

    // overridden virtual functions omitted (not using smart pointers)

    MeasurementDevice* get_measurement_device() {
    return this;
    }
    };

    这些是类似工厂的函数,负责创建 ConnMgrMeasurementDevice对象:
    typedef std::map<std::string, boost::any> Config;

    ConnMgr* create_conn_mgr(const Config& cfg) {
    const std::string& type =
    boost::any_cast<std::string>(cfg.find("type")->second);
    const std::string& addr =
    boost::any_cast<std::string>(cfg.find("addr")->second);

    ConnMgr* ep;
    if (type == "aggregated") ep = new AggrSystem(addr);
    else if (type == "standalone") ep = new StandAloneSystem(addr);
    else throw std::runtime_error("Unknown type");
    return ep;
    }

    MeasurementDevice* get_measurement_device(ConnMgr* ep, const Config& cfg) {
    const std::string& type =
    boost::any_cast<std::string>(cfg.find("type")->second);

    if (type == "aggregated") {
    int slot = boost::any_cast<int>(cfg.find("slot")->second);
    AggrSystem* aggr_sys = dynamic_cast<AggrSystem*>(ep);
    return aggr_sys->get_measurement_device(slot);
    }
    else if (type == "standalone") return dynamic_cast<StandAloneSystem*>(ep);
    else throw std::runtime_error("Unknown type");
    }

    最后是 main() ,展示了一个非常简单的使用案例:
    #define USE_AGGR

    int main() {
    Config config = {
    { "addr", boost::any(std::string("192.168.1.10")) },
    #ifdef USE_AGGR
    { "type", boost::any(std::string("aggregated")) },
    { "slot", boost::any(1) },
    #else
    { "type", boost::any(std::string("standalone")) },
    #endif
    };

    ConnMgr* ep = create_conn_mgr(config);
    ep->connect();

    MeasurementDevice* dev = get_measurement_device(ep, config);
    std::vector<char> data; // in real life data should contain something
    dev->send_data(data);

    ep->disconnect();
    delete ep;
    return 0;
    }

    提议的变更

    首先,我想知道是否有办法避免 dynamic_castget_measurement_device .自 AggrSystem::get_measurement_device(int slot)StandAloneSystem::get_measurement_device()有不同的签名,不可能在基类中创建一个公共(public)的虚拟方法。我正在考虑添加一个接受 map 的通用方法包含选项(例如,插槽)。在那种情况下,我不需要进行动态转换。就更简洁的设计而言,第二种方法是否更可取?

    为了将类层次结构移植到智能指针,我使用了 unique_ptr .首先我改了 map AggrSystem 中的组件数量到:
    std::map<int, std::unique_ptr<Component> > components_;

    新增 Component现在看起来像:
    void AggrSystem::add_component(int slot) {
    if (is_slot_used(slot)) throw std::runtime_error("Slot already used");
    components_.insert(std::make_pair(slot,
    std::unique_ptr<Component>(new Component(*this, slot))));
    }

    返回 Component我决定从 Component 的生命周期开始返回一个原始指针对象由 AggrSystem 的生命周期定义目的:
    MeasurementDevice* AggrSystem::get_measurement_device(int slot) {
    if (!is_slot_used(slot)) throw std::runtime_error("Empty slot");
    return components_.find(slot)->second.get();
    }

    返回原始指针是正确的决定吗?如果我使用 shared_ptr ,但是,然后我遇到了独立系统的实现问题:
    MeasurementDevice* StandAloneSystem::get_measurement_device() {
    return this;
    }

    在这种情况下,我无法返回 shared_ptr使用 this .我想我可以创建一个额外的间接级别,并有类似 StandAloneConnMgr 的东西。和 StandAloneMeasurementDevice ,第一个类将举行 shared_ptr到第二个实例。

    所以,总的来说,我想问一下在使用智能指针时这是否是一个好方法。最好使用 mapshared_ptr并返回 shared_ptr也是,还是基于使用 unique_ptr 的当前方法更好所有权和访问原始指针?

    附注: create_conn_mgrmain也进行了更改,因此现在我使用 ConnMgr* 而不是使用原始指针( unique_ptr<ConnMgr> ) .我没有添加代码,因为问题已经足够长了。

    最佳答案

    First of all, I wonder whether there is a way to avoid the dynamic_cast in get_measurement_device.



    我会尝试统一 get_measurement_device签名,以便您可以将其设为基类中的虚函数。

    So, overall, I wanted to ask whether this a good approach when using smart pointers.



    我认为你做得很好。您基本上已将“单一所有权”新闻和删除内容转换为 unique_ptr以一种相当机械的方式。这完全是正确的第一步(也可能是最后一步)。

    我也认为您从 get_measurement_device 返回原始指针的决定是正确的。因为在您的原始代码中,此函数的客户端没有获得此指针的所有权。当您不打算共享或转移所有权时处理原始指针是大多数程序员都会认识到的好模式。

    总之,您已经正确地将现有设计转换为使用智能指针,而没有更改设计的语义。

    从这里开始,如果您想研究将您的设计更改为涉及共享所有权的设计的可能性,那么下一步是完全有效的。我自己的偏好是更喜欢独特的所有权设计,直到用例或环境需要共享所有权。

    唯一所有权不仅更有效,而且更容易推理。这种推理的简便性通常会减少意外的循环内存所有权模式(循环内存所有权 == 内存泄漏)。每次看到指针时都只删除 shared_ptr 的编码人员更有可能以内存所有权循环结束。

    也就是说,循环内存所有权也可以仅使用 unique_ptr .如果发生这种情况,您需要 weak_ptr打破循环,和 weak_ptr仅适用于 shared_ptr .因此,所有权周期的引入是迁移到 shared_ptr 的另一个很好的理由。 .

    关于c++ - 将现有的类结构移植到智能指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11037011/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com