【问题标题】:Throwing exception from constructor memory leak从构造函数内存泄漏引发异常
【发布时间】:2018-11-18 22:19:00
【问题描述】:

在这段代码中,如果if 子句为真,则CurrentAccount 构造函数会抛出异常:

void Bank::createAccount(string accountType,int iban,int ownerid,double amount)
{
    Account* toAddAccount=nullptr;
    if(accountType=="CurrentAccount")
    {
        toAddAccount=new CurrentAccount(iban,ownerid,amount);
    }
}

如你所见,异常并没有在这个方法中被捕获,而是在堆栈中被提升到更高的位置。

我想知道,由于我不删除toAddAccountCurrentAccount 构造函数仅适用于整数),会不会出现内存泄漏?

【问题讨论】:

  • 不,CurrentAccount 永远不会被创建,因为构造函数永远不会运行到完成,所以没有什么要删除的。
  • 抛出异常时没有泄漏,因为它将中止CurrentAccount对象的构造。由于没有完全创建CurrentAccount 对象,因此以后不需要释放它。但是,如果 CurrentAccount 构造函数没有抛出异常,则存在泄漏,因为您没有删除 toAddAccount...
  • 如果您使用std::unique_ptr,您不必担心内存泄漏..
  • 更重要的是,如果构造函数抛出,则 operator new 的代码调用匹配的 operator delete 以释放分配的内存块(不调用析构函数(因为对象不'存在' ) 但运算符 delete 是)。
  • @RemyLebeau 是真的。更多的是推广智能指针的使用...

标签: c++ memory-management


【解决方案1】:

这不是泄漏,因为如果在执行过程中抛出异常,“新表达式”负责清理。换句话说,“新表达式”分配内存,然后调用CurrentAccount 的构造函数。如果此构造函数抛出“新表达式”,则会自动释放先前分配的内存。

【讨论】:

  • 还需要注意的是,编译器抛出异常之前成功构造的任何类成员都会被编译器自动销毁.但是,在抛出异常之前分配有new 的任何成员都需要在异常转义构造函数之前为delete'd(通过try/catch、智能指针等),否则它们将被泄漏。
  • 这就是为什么您应该始终使用 RAII。
【解决方案2】:

我认为这个问题已经得到解答,但是您在构建对象时应该使用RAII。具体来说(正如已经多次指出的那样)是使用std::unique_ptr(和make_unique,具体取决于您的标准)。

Account* Bank::createAccount(string accountType,int iban,int ownerid,double amount)
{
    std::unique_ptr<Account> toAddAccount;
    if(accountType=="CurrentAccount")
    {
        toAddAccount=new CurrentAccount(iban,ownerid,amount);
    }

    // presumably more code

    return toAddAccount.release(); // your factories shouldn't care where your accounts are stored.
}

【讨论】:

  • 在这种特定情况下,使用 unique_ptr 没有任何意义。 CurrentAccount 对象永远不会被构造,因此没有什么可破坏的,为其分配的内存由编译器生成的代码释放。
  • 我同意。在 OP 问题的特定边缘情况下,没有什么可破坏的。在一般实践中,当构造函数完成并且故障出在其他地方时,您将使用 RAII 技术来防止内存泄漏。
猜你喜欢
  • 2019-08-19
  • 1970-01-01
  • 2020-11-02
  • 2021-06-17
  • 2013-01-12
  • 2013-05-20
  • 2021-07-07
  • 2014-11-15
  • 1970-01-01
相关资源
最近更新 更多