#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在输出中看到.
由于在抛出异常之前完全构造Base了DerivedWAS 的部分~Base(),因此IS会自动调用,因此您可以Base::dtor在输出中看到.
由于Derived对象未完全构造,~Derived()因此不会被调用,因此您不会Derived::dtor在输出中看到.
简而言之,只要异常转义构造函数,只有已成功构造的类(基类和数据成员等)的各个部分才会被单独自动销毁.未完全构造的碎片不会自动销毁.C++标准保证了这种行为.
当异常向上传播调用堆栈时,它会中止它转义的任何构造函数,直到捕获到异常,或者异常转义main()导致进程终止.