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中;但这是一个不同的话题。

  1. 删除commInterface;仅此而已!:) 最后将其全部删除 程序.

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