为什么构造函数抛出异常时会出现内存泄漏?

Ney*_*r87 3 c++ memory-leaks exception c++11

我读了Paul Deitel《C++ How to Program 8th Edition》一书。第 645 页有一个声明:

当在 new 表达式中创建的对象的构造函数抛出异常时,会释放该对象动态分配的内存。

为了验证这个说法,我编写了如下代码:

#include <iostream>
#include <exception>
#include <memory>

class A{
public:
  A(){std::cout << "A is coming." << std::endl;}
  ~A(){std::cout << "A is leaving." << std::endl;}
};
class B
{
public:
  B()
  {
    std::cout << "B is coming." << std::endl;
    A b;
    throw 3;
  }
  ~B(){std::cout << "B is leaving." << std::endl;}
};

int main(void)
{
    try
    {
        std::shared_ptr<B> pi(new B);
    }
    catch(...)
    {
      std::cout << "Exception handled!" << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

B is coming.
A is coming.
A is leaving.
Exception handled!
Run Code Online (Sandbox Code Playgroud)

这表明B的析构函数没有被调用,这似乎与上面的说法相冲突。

我的代码是否正确以验证该声明?如果不是,我应该如何修改?如果是的话,是否说明这个说法是错误的?

Lig*_*ica 5

你混淆了两件事:

\n\n
    \n
  • 内存被释放
  • \n
  • 被调用的析构函数
  • \n
\n\n

你已经证明后者不会发生,这是有道理的:你怎么能摧毁那些没有正确建造的东西呢?但请注意,成员变量的析构函数被调用,因为当构造函数抛出异常时,所有成员变量都已完全构造完毕。

\n\n

但这与内存释放无关,内存释放肯定发生。

\n\n
\n

[C++11: 15.2/2]:任何存储持续时间的对象,其初始化或销毁因异常而终止,将为它的所有完全构造的子对象(不包括类联合类的变体成员)执行析构函数,即,对于其主构造函数( 12.6.2) 已完成执行,析构函数尚未开始执行。类似地,如果对象的非委托构造函数已完成执行,并且该对象的委托构造函数因异常退出,则将调用 object\xe2\x80\x99s 析构函数。如果对象是在 new 表达式中分配的,则调用匹配的释放函数(3.7.4.2、5.3.4、12.5)(如果有)来释放该对象占用的存储空间。

\n
\n