C ++ app:如何正确删除/释放已分配的对象?

时间:2017-01-18 09:15:22

标签: c++ c++11 pointers memory-management smart-pointers

我在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)我没有使用(并且不想使用)提升
提前感谢您的时间和耐心。

6 个答案:

答案 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)

  1. 删除commInterface;这就是全部!:)在最后删除它 程序

  2. 为什么要做很多对象。我正在开发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)。