C++ 应用程序:如何正确 delete/release 分配的对象?
C++ app: How to properly delete/release an allocated object?
我在 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()
并多次调用它,我将有很多未取消分配的内存。
上面的代码是一个简化版本。其实代码有很多exitpoints/returns。它还具有一些抛出异常的函数(我不是 100% 确定它们都被正确捕获和处理)。
所以,我想在这种情况下,在所有 returns
之前添加 delete commInterface;
是不够的...
因此,我的问题是:有没有办法正确地 delete/release commInterface
以便嵌入和使用上述模块而不用担心内存泄漏?也许是智能指针或其他一些想法...?
两句备注:
1) 我启用了 C++11;
2) 我没有使用(也不想使用)boost.
预先感谢您的时间和耐心。
以我的愚见,这是一个 global variables 应该避免的方案。
使用智能指针以下列方式完成RAII and in particular 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);
还请注意,使用建议的方案,每次调用 commFunction
时都会创建一个新的 UartComm
对象。如果 UartComm
的创建是一项昂贵的操作,或者如果您的设计需要重用单个 UartComm
对象,则可以将 singleton pattern 用于 UartComm
对象。
我想 commInterface
是要提供给应用程序其他部分的单例。我进一步假设,您想确保在应用程序中使用单例对象时对其进行初始化。
然后,我建议将变量设置为 static
以便不将其暴露给其他翻译单元(然后可能会在未初始化状态下访问它);相反,提供一个访问器函数,如 UartComm *getCommInterface ()
。在访问变量之前,检查它是否被初始化。请参阅下面的代码作为示例:
static UartComm* commInterface = nullptr;
void commInit()
{
if (!commInterface)
commInterface = new UartComm;
}
UartComm *getCommInterface () {
commInit();
return commInterface;
}
注意,当你用C++编程时,你也应该考虑将这种单例机制封装在一些class中;但这是一个不同的话题。
删除commInterface
;仅此而已!:) 最后将其全部删除
程序.
为什么对象很多。我正在为 RS-232 开发应用程序
端口 (COM-port) 并且它有 1 个对象 "RS-232" 用于通信。要么
你有以太网连接吗?
Is there a way to properly delete/release commInterface in order to embed and use the above module without worrying about memory leaks? Smart pointer maybe or some other idea...?
这是另一个想法:使用静态实例。它将在第一次使用时构建,并在程序结束时销毁。这也将比动态分配更快(尽管对于单个分配来说并不重要)。
UartComm& commInterface() {
static UartComm interface;
return interface;
}
一般规则是必须释放动态分配的对象。并且每种形式的分配都需要相应的释放。
虽然现代操作系统通常会在程序结束时为您清理(不需要使用运算符 delete
),但依赖它是一个坏习惯 - 并非所有操作系统都能保证。操作系统确实有错误。此外,还有你的情况 - 如果你发现你想将 main()
重命名为其他东西以重用它,你就会遇到内存泄漏问题 - 如果你在代码中清理,你的问题很容易避免,而不是在程序退出时依赖清理。
在你的情况下,分配是
commInterface = new UartComm;
所以对应的释放是
delete some_pointer;
其中 some_pointer
可能是 commInterface
(假设它是可见的)或另一个存储相同值的相同类型的指针。
一般而言,还有许多其他方法可以确保正确释放对象。例如;
- 在分配它的同一个函数中释放它。问题是阻止对象在函数 returns.
之后被使用
Return指向调用者的指针,调用者释放。
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
}
当然,还有许多其他选择。例如,根本不使用动态分配,而只是 return 按值分配一个对象。
如果您可以删除全局变量,我会选择 user2079303 提供的单例解决方案或 101010 的本地 unique_ptr 版本。哪一个取决于您是否想在每次调用时重新创建接口你的 commFunction()
与否。
如果 removing/changing 全局变量不可能 我看到两种可能性,代码更改最少(同样取决于您是否要重新创建对象):
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;
}
同样,这些不是我一般推荐的解决方案,但在前面提到的限制下,它们可能是您能做的最好的。
另请记住,none 这些解决方案是线程安全的(即使 UartComm 是)。
我在 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()
并多次调用它,我将有很多未取消分配的内存。
上面的代码是一个简化版本。其实代码有很多exitpoints/returns。它还具有一些抛出异常的函数(我不是 100% 确定它们都被正确捕获和处理)。
所以,我想在这种情况下,在所有 returns
之前添加 delete commInterface;
是不够的...
因此,我的问题是:有没有办法正确地 delete/release commInterface
以便嵌入和使用上述模块而不用担心内存泄漏?也许是智能指针或其他一些想法...?
两句备注:
1) 我启用了 C++11;
2) 我没有使用(也不想使用)boost.
预先感谢您的时间和耐心。
以我的愚见,这是一个 global variables 应该避免的方案。
使用智能指针以下列方式完成RAII and in particular 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);
还请注意,使用建议的方案,每次调用 commFunction
时都会创建一个新的 UartComm
对象。如果 UartComm
的创建是一项昂贵的操作,或者如果您的设计需要重用单个 UartComm
对象,则可以将 singleton pattern 用于 UartComm
对象。
我想 commInterface
是要提供给应用程序其他部分的单例。我进一步假设,您想确保在应用程序中使用单例对象时对其进行初始化。
然后,我建议将变量设置为 static
以便不将其暴露给其他翻译单元(然后可能会在未初始化状态下访问它);相反,提供一个访问器函数,如 UartComm *getCommInterface ()
。在访问变量之前,检查它是否被初始化。请参阅下面的代码作为示例:
static UartComm* commInterface = nullptr;
void commInit()
{
if (!commInterface)
commInterface = new UartComm;
}
UartComm *getCommInterface () {
commInit();
return commInterface;
}
注意,当你用C++编程时,你也应该考虑将这种单例机制封装在一些class中;但这是一个不同的话题。
删除
commInterface
;仅此而已!:) 最后将其全部删除 程序.为什么对象很多。我正在为 RS-232 开发应用程序 端口 (COM-port) 并且它有 1 个对象 "RS-232" 用于通信。要么 你有以太网连接吗?
Is there a way to properly delete/release commInterface in order to embed and use the above module without worrying about memory leaks? Smart pointer maybe or some other idea...?
这是另一个想法:使用静态实例。它将在第一次使用时构建,并在程序结束时销毁。这也将比动态分配更快(尽管对于单个分配来说并不重要)。
UartComm& commInterface() {
static UartComm interface;
return interface;
}
一般规则是必须释放动态分配的对象。并且每种形式的分配都需要相应的释放。
虽然现代操作系统通常会在程序结束时为您清理(不需要使用运算符 delete
),但依赖它是一个坏习惯 - 并非所有操作系统都能保证。操作系统确实有错误。此外,还有你的情况 - 如果你发现你想将 main()
重命名为其他东西以重用它,你就会遇到内存泄漏问题 - 如果你在代码中清理,你的问题很容易避免,而不是在程序退出时依赖清理。
在你的情况下,分配是
commInterface = new UartComm;
所以对应的释放是
delete some_pointer;
其中 some_pointer
可能是 commInterface
(假设它是可见的)或另一个存储相同值的相同类型的指针。
一般而言,还有许多其他方法可以确保正确释放对象。例如;
- 在分配它的同一个函数中释放它。问题是阻止对象在函数 returns. 之后被使用
Return指向调用者的指针,调用者释放。
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 }
当然,还有许多其他选择。例如,根本不使用动态分配,而只是 return 按值分配一个对象。
如果您可以删除全局变量,我会选择 user2079303 提供的单例解决方案或 101010 的本地 unique_ptr 版本。哪一个取决于您是否想在每次调用时重新创建接口你的 commFunction()
与否。
如果 removing/changing 全局变量不可能 我看到两种可能性,代码更改最少(同样取决于您是否要重新创建对象):
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;
}
同样,这些不是我一般推荐的解决方案,但在前面提到的限制下,它们可能是您能做的最好的。
另请记住,none 这些解决方案是线程安全的(即使 UartComm 是)。