我在Ubuntu 14.04上使用GCC编译器 我有一个小的沟通应用程序(不是我写的),我打算将它嵌入我自己的应用程序中 小通讯。应用代码如下所示:
UartComm * commInterface;
...
void commInit()
{
commInterface = new UartComm;
}
// other functions here that use "commInterface"
// ...
int main()
{
commInit();
...
if(smthing_1)
return (-1);
if(smthing_2)
return (-2);
...
if(smthing_n)
return (-n);
//
return (0);
}
-
如上所示,原始代码中没有delete commInterface;
,因此,如果我将上述代码嵌入到我的应用中,将main()
重命名为commFunction()
并多次调用它,我会有很多没有解除分配的内存
以上代码是简化版。实际上,代码有许多退出点/返回。它还有一些抛出异常的函数(我不是100%确定它们都被捕获并正确处理)
所以,我想在所有delete commInterface;
之前添加returns
在这种情况下是不够的...
因此,我的问题是:有没有办法正确删除/释放commInterface
以嵌入和使用上述模块而不用担心内存泄漏?智能指针可能还是其他一些想法......?
两个评论 :
1)我启用了C ++ 11;
2)我没有使用(并且不想使用)提升。
提前感谢您的时间和耐心。
答案 0 :(得分:3)
在我看来,这是一个global variables要避免的方案。
使用智能指针以下列方式完成RAII,特别是std::unique_ptr
:
int commFunction() {
auto commInterface = std::make_unique<UartComm>();
...
if(smthing_1)
return (-1);
if(smthing_2)
return (-2);
...
if(smthing_n)
return (-n);
//
return (0);
}
请注意std::make_unique
是C ++ 14,或者C ++ 11使用以下内容:
std::unique_ptr<UartComm> commInterface(new UartComm);
还要注意,使用建议的方案,每次调用UartComm
时都会创建一个新的commFunction
对象。如果创建UartComm
是一项昂贵的操作,或者您的设计需要重复使用单个UartComm
对象,则可以使用singleton pattern作为UartComm
对象。
答案 1 :(得分:2)
有没有办法正确删除/释放commInterface以嵌入和使用上述模块而不必担心内存泄漏?智能指针可能还是其他一些想法......?
这是另一个想法:使用静态实例。它将在首次使用时构建,并在程序结束时销毁。这也会比动态分配更快(但是,对于单个分配来说,这并不重要)。
UartComm& commInterface() {
static UartComm interface;
return interface;
}
答案 2 :(得分:1)
我认为commInterface
是要提供给应用程序其他部分的单例。我想还有一点,你想确保在应用程序中使用singleton objet时初始化它。
然后,我建议创建变量static
,以便不将它暴露给其他翻译单元(然后可以在未经过消毒的状态下访问它);相反,提供像UartComm *getCommInterface ()
这样的访问函数。在访问变量之前,请检查它是否已初始化。请参阅下面的代码作为示例:
static UartComm* commInterface = nullptr;
void commInit()
{
if (!commInterface)
commInterface = new UartComm;
}
UartComm *getCommInterface () {
commInit();
return commInterface;
}
请注意,在C ++中编程时,您还应该考虑在某个类中封装这个单例机制;但那是一个不同的主题。
答案 3 :(得分:1)
删除commInterface
;这就是全部!:)在最后删除它
程序
为什么要做很多对象。我正在开发RS-232应用程序 端口(COM端口),它有1个对象&#34; RS-232&#34;用于沟通。要么 你有以太网连接吗?
答案 4 :(得分:1)
一般规则是必须释放动态分配的对象。并且每种形式的分配都需要相应的释放。
虽然现代操作系统通常会在程序结束时为您清理(不需要使用运算符delete
),但依赖于此是一种坏习惯 - 并非所有操作系统都能提供这种保证。操作系统确实存在错误。此外,还有你的情况 - 如果你发现你想要将main()
重命名为其他东西以便重复使用它,你就会遇到内存泄漏的问题 - 如果你在代码中清理了你的问题就很容易避免了,而不是在程序退出时依赖清理。
在您的情况下,分配是
commInterface = new UartComm;
所以相应的重新分配是
delete some_pointer;
其中some_pointer
可能是commInterface
(假设它是可见的)或另一个相同类型的指针,它存储相同的值。
一般而言,还有许多其他方法可以确保正确释放对象。例如;
将指针返回给调用者,调用者将其释放。
UartComm *commInit()
{
UartComm *commInterface = new UartComm;
// whatever
return commInterface;
}
int main()
{
UartComm *x = commInit();
// whatever
delete x;
}
与上述类似,但使用智能指针,因此无需手动解除分配(智能指针就是这样)。
std::unique_pointer<UartComm> commInit()
{
std::unique_pointer<UartComm> commInterface(new UartComm);
// whatever
return commInterface;
}
int main()
{
std::unique_pointer<UartComm> x = commInit();
// whatever
// x will be cleaned up as main() returns - no need to release
}
当然,还有很多其他选择。例如,根本不要使用动态分配,只需按值返回一个对象。
答案 5 :(得分:1)
如果您可以删除全局变量,我会使用user2079303提供的单例解决方案或101010的本地unique_ptr版本。哪一个取决于您每次调用commFunction()
时是否要重新创建接口或不。
如果无法删除/更改全局变量,我会看到两种可能性,代码更改最少(同样取决于您是否要重新创建对象):
UartComm * commInterface = nullptr; //nullptr not necessary but makes it more explicit
...
void commInit()
{
//only create commInterface the first time commInit() is called
if( !commInterface )
commInterface = new UartComm;
}
或
UartComm * commInterface = nullptr; //nullptr not necessary but makes it more explicit
...
void commInit()
{
//destruct old UartComm and create new one each time commInit is called
delete commInterface;
commInterface = new UartComm;
}
同样,这些不是我一般建议的解决方案,但根据前面提到的限制,它们可能是你能做的最好的。
还要记住,这些解决方案都不是线程安全的(即使是UartComm)。