我很好奇是否有一种优雅的方法来解决c ++中的以下问题:
我有一个模拟器应用程序,其中包含通过通道连接的多个组件。通道可以是网络通道(需要app的两个实例)或虚拟本地通道。有两个接口:IChannelIn
和IChannelOut
以及两个相应的变量:
IChannelIn* in;
IChannelOut* out;
DummyChannel
同时为IChannelIn
和IChannelOut
。它只是将输入复制到输出。还有TCPChannelIn: public IChannelIn
和单独的TCPChannelOut: public IChannelOut
。
现在,根据用户的选择,我要么创建一个DummyChannel
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
删除已删除的内容。
这是否有一种优雅的方式?
答案 0 :(得分:9)
你需要的是:
~App::App()
{
if (in != out)
{
delete out;
}
delete in;
}
当通道不同时,指针会有所不同。
但是,正如danatel在评论中指出的那样in
和out
无法比较。一个安全(但不优雅)的解决方案是使用dummy
标志。如果将in
和out
设置为虚拟通道,则析构函数将变为:
~App::App()
{
if (!dummy)
{
delete out;
}
delete in;
}
虽然我对此不满意。
我目前唯一能够看到的其他解决方案是更改IChannelIn
和IChannelOut
的定义,以便可以安全地进行比较。
答案 1 :(得分:7)
如果您正在使用boost,可以考虑使用boost::shared_ptr这将在最后一个实例发布时自动删除该对象。
答案 2 :(得分:3)
if (in == out) {
delete in;
}
else {
delete in;
delete out;
}
答案 3 :(得分:3)
经验法则:将new
与delete
匹配。
~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;
}
唯一的解决方案似乎是使用智能引用计数指针。
答案 4 :(得分:3)
你的类如何知道这是一个freestore指针?例如。什么说反对以下代码?
DummyChannel d;
in = &d;
out = &d;
这是一段完全合理的代码,但在尝试删除任何一个指针时,析构函数会崩溃。
长话短说:回收资源是首先分配资源的人的工作。如果你的类传递了一个指针,那么该类就无法知道并且不关心重新分配。这完全是来电者的责任。
如前所述,在不使客户做大量工作的情况下解决这种困境的优雅方法是智能指针。
答案 5 :(得分:0)
我总是在设计时考虑对象所有权:
当试图回答这些问题时,我也决定了实现它的方法(析构函数,智能指针等)。
答案 6 :(得分:0)
不要忘记将IChannelIn和IChannelOut析构函数设置为虚拟。如果析构函数不是虚拟的,则在调用IChannel析构函数时(即删除IChannel ptr内容时)不会调用TCPChannel或DummyChannel析构函数。