智能指针:是否创建了对象的"基础"部分?

ars*_*ium 0 c++ c++11 c++14

#include <iostream>
#include <memory>
class Member {
public:
  Member() {
    std::cout << "Member::ctor" << std::endl;
    throw "Exception";
  }
  ~Member() {
    std::cout << "Member::dtor" << std::endl;
  }
};
class Base {
public:
  Base() {
    std::cout << "Base::ctor" << std::endl;
  }
  virtual ~Base() {
    std::cout << "Base::dtor" << std::endl;
  }
};

class Derived : public Base {
  Member* m_;
  public:
    Derived() : m_(new Member()) {
      std::cout << "Derived::ctor" << std::endl;
    }
  ~Derived() {
    if(m_) delete m_;
      std::cout << "Derived::dtor" << std::endl;
    }
};

int main(int argc, char** argv) {
try{
  std::unique_ptr<Base> b = std::make_unique<Derived>();
  std::cout << "No Exception" << std::endl;
  }
  catch(...)
  {
    std::cout << "Exception" << std::endl;
  }
}
Run Code Online (Sandbox Code Playgroud)

上述程序的输出是:

Base::ctor
Member::ctor
Base::dtor
Exception
Run Code Online (Sandbox Code Playgroud)

不明白为什么会这样.当对象无法完全构造时,派生对象的一部分是否会杀死对象的基本部分?

有人可以解释原因吗?

Rem*_*eau 11

构造函数在进入其自己的主体之前处理其成员初始化列表.所以,在这种情况下,Derived()调用Base()Member(),按照这个顺序,进入自己的身体了.

Derived()第一次调用Base()(隐式地,因为你没有Base()Derived()成员初始化列表中明确指定).Base()输入正文,因此您可以Base:::ctor在输出中看到.没有异常被抛出,所以Base()通常会退出.

Derived()继续打电话给Member()下一个.Member()输入正文,因此您可以Member::ctor在输出中看到.但是Member()在退出之前会抛出异常,因此Member对象的构造会中止.

异常进入和退出Derived(),因此Derived()也被中止.由于Derived()从其成员初始化列表中被中止,因此未输入其正文,因此您不会Derived::ctor在输出中看到.

由于Member对象未完全构造,~Member()因此不会被调用,因此您不会Member::dtor在输出中看到.

由于在抛出异常之前完全构造BaseDerivedWAS 的部分~Base(),因此IS会自动调用,因此您可以Base::dtor在输出中看到.

由于Derived对象未完全构造,~Derived()因此不会被调用,因此您不会Derived::dtor在输出中看到.

简而言之,只要异常转义构造函数,只有已成功构造的类(基类和数据成员等)的各个部分才会被单独自动销毁.未完全构造的碎片不会自动销毁.C++标准保证了这种行为.

当异常向上传播调用堆栈时,它会中止它转义的任何构造函数,直到捕获到异常,或者异常转义main()导致进程终止.