来自相关的c ++标准部分:
引用构造函数的函数try-block中的对象的任何非静态成员或基类,或者该对象的析构函数导致未定义的行为。
例如。
T::~T()
{
try {
this->nonstatic_member; // iff I read the quote correctly
} catch( ... ) {
}
}
那么为什么这种未定义的行为?
答案 0 :(得分:7)
我认为在析构函数的函数try-block中访问非静态数据成员的原因是[except.ctor] / 2和[except.handle] / 11保证进入所述try-block的catch子句时,所有子对象都已被销毁:
2014年12月23日的github草案,[except.ctor] / 2
任何存储持续时间的对象,其初始化或销毁 由异常终止将为所有人执行析构函数 其完全构建的子对象(不包括变体成员) 一个类似联合的类),即对于主体的子对象 构造函数已完成执行,析构函数尚未完成 开始执行。
<强> [except.handle] / 11 强>
[...]基类和非变体成员 在进入a的处理程序之前,应该销毁一个对象 该对象的析构函数的 function-try-block 。
因此,无论我们是在类本身的dtor中还是在子对象的dtor中抛出异常:所有子对象都将被销毁。
#include <iostream>
struct loud
{
~loud() { std::cout << "~loud()\n"; }
};
struct T
{
loud l;
~T() noexcept(false)
try
{
std::cout << "throwing an int\n";
throw 42;
}catch(int)
{
std::cout << "caught an int\n";
throw;
}
};
int main()
{
try
{
T t;
}catch(...)
{
std::cout << "caught an exception in main\n";
}
}
输出:
throwing an int ~loud() caught an int caught an exception in main
#include <iostream>
struct loud
{
loud() { std::cout << "loud()\n"; }
~loud() { std::cout << "~loud()\n"; }
};
struct A
{
A() { std::cout << "A()\n"; }
~A() noexcept(false) { std::cout << "~A()\n"; throw 42; }
};
struct T
{
loud l;
A a;
~T() noexcept(false)
try
{
}catch(int)
{
std::cout << "caught an int\n";
throw;
}
};
int main()
{
try
{
T t;
}catch(...)
{
std::cout << "caught an exception in main\n";
}
}
输出:
loud() A() ~A() ~loud() caught an int caught an exception in main
答案 1 :(得分:5)
处理处理程序时,非静态成员可能尚未创建或已被销毁。
并且您的示例未演示函数try-block。当两个子对象都没有被销毁时,它是析构函数体内的一个try-block。
这里是构造函数的函数try块的一个例子
T::T(int ii, double id)
try : i(f(ii)), d(id)
{
// constructor statements
}
catch (...)
{
// handles exceptions thrown from the ctor-initializer
// and from the constructor statements
}
答案 2 :(得分:2)
用
struct S
{
S() try
: m()
{
}
catch(...)
{
// this->non_static is UB
}
~S()
try
{
}
catch(...)
{
// this->non_static is UB
}
private:
Member m;
};
当您在catch块中时,无法确定异常的来源以及初始化/销毁哪个对象。