代码之家  ›  专栏  ›  技术社区  ›  danatel

由两个指针引用的C++删除对象

c++
  •  4
  • danatel  · 技术社区  · 15 年前

    我只是好奇,如果有一个优雅的方式来解决以下问题在C++中:

    我有一个模拟器应用程序,它包含几个由通道连接的组件。通道可以是网络通道(需要两个应用程序实例)或虚拟本地通道。有两个接口: IChannelIn IChannelOut 以及两个相应的变量:

    IChannelIn* in;
    IChannelOut* out;
    

    这个 DummyChannel 都是 鱼藤酮 伊坎内洛特 . 它只是将输入复制到输出。也有 TCPChannelIn: public IChannelIn 分开 TCPChannelOut: public IChannelOut .

    现在,根据用户的选择,我或者创建一个 虚拟通道

    DummyChannel* d = new DummyChannel;
    in = d;
    out = d;
    

    或两个单独的对象: in = new TCPChannelIn; out = new TcpChannelOut

    问题是:析构函数应该做什么?

    ~App::App()
    {
        delete in;
        delete out;
    }
    

    以错误结束,因为 delete in; 同时删除了虚拟通道 d 以便 delete out 删除已删除的内容。

    有没有一种优雅的方法可以解决这个问题?

    7 回复  |  直到 15 年前
        1
  •  3
  •   Graeme Perrow    15 年前

    你们班怎么样 知道 这是一个自由存储指针?例如,什么与以下代码不符?

    DummyChannel d;
    in = &d;
    out = &d;
    

    这是一段完全合理的代码,但是您的析构函数 尝试删除任何指针时崩溃。

    长话短说:资源回收首先是分配资源的人的工作。如果您的类被传递一个指针,那么该类将不知道也不关心释放。这完全是呼叫者的责任。

    正如前面提到的,解决这种困境而不让客户做很多工作的优雅方法是智能指针。

        2
  •  9
  •   ChrisF    15 年前

    你需要的是:

    ~App::App()
    {
        if (in != out)
        {
            delete out;
        }
        delete in;
    }
    

    当通道不同时,指针也会不同。

    然而,正如丹纳特尔在评论中指出的那样 in out 不可比。一个安全(但不美观)的解决方案是使用 dummy 旗帜。设置中频 在里面 外面的 如果设置为虚拟通道,析构函数将变为:

    ~App::App()
    {
        if (!dummy)
        {
            delete out;
        }
        delete in;
    }
    

    尽管我对此不满意。

    目前我唯一能看到的其他解决方案是更改 IChannelIn IChannelOut 以便安全地进行比较。

        3
  •  7
  •   Stephen Nutt    15 年前

    如果你正在使用Boost,你可以考虑使用 boost::shared_ptr 这将在释放最后一个实例时自动删除该对象。

        4
  •  3
  •   Brian    15 年前
    if (in == out) {
        delete in;
    }
    else {
        delete in;
        delete out;
    }
    

    ?

        5
  •  3
  •   dirkgently    15 年前

    经验法则:匹配 new 随你 delete S.

    ~App::App()
    {
        delete out;
        // the next line tries to free
        // memory no longer in the app's
        // control invoking UB
        delete in;
    }
    

    在这里,你会遇到经典 双自由 问题。

    ~App::App()
    {
        if (in != out)
        {
            delete out;
        }
        // if in == out the out object is not deleted
        // for a non trivial object this tantamounts to
        // leaking resources held by TCPChannelOut other
        // than d
        delete in;
    }
    

    唯一的解决方案似乎是使用一个智能引用计数指针。

        6
  •  0
  •   Cătălin Pitiș    15 年前

    我总是在设计时考虑对象所有权:

    • 谁创建了对象?
    • 谁拥有(因此删除 对象)?
    • 我怎样才能避免引用 已被破坏的对象 (或者我如何确定 引用的对象仍然有效或 不是吗?

    当试图回答这些问题时,我也决定了实现它的方法(析构函数、智能指针等)。

        7
  •  0
  •   DanM    15 年前

    别忘了让你的ichannelin和ichannelout析构函数虚拟化。如果析构函数不是虚拟的,则在调用ichannel析构函数时(即删除ichannel ptr内容时),不会调用tcpchannel或dummychannel析构函数。