ISO c ++ 15.3.10:为什么这种未定义的行为?

Nik*_*iou 4 c++ language-lawyer c++11

从相关的c ++标准部分:

引用构造函数的函数try-block的处理程序中的对象的任何非静态成员或基类,或该对象的析构函数导致未定义的行为.

例如.

T::~T() 
{
      try {
        this->nonstatic_member; // iff I read the quote correctly
      } catch( ... ) {
      }
}
Run Code Online (Sandbox Code Playgroud)

那为什么这个未定义的行为?

dyp*_*dyp 8

我认为在析构函数的函数try-block中访问非静态数据成员的原因是[except.ctor]/2和[except.handle]/11保证所有子对象在进入catch时都已被销毁-clause of try-block:

2014年2月23日的github草案,[except.ctor]/2

任何存储持续时间的对象,其初始化或销毁由异常终止,将为其所有完全构造的子对象(不包括类似联合的类的变体成员)执行析构函数,即对于主构造函数具有的子对象.已完成执行,析构函数尚未开始执行.

[except.handle]/11

[...]在进入该对象的析构函数的function-try-block的处理程序之前,应销毁对象的基类和非变体成员 .

因此,无论我们是在类本身的dtor中还是在子对象的dtor中抛出异常:所有子对象都将被销毁.


例1:

#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";
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

throwing an int
~loud()
caught an int
caught an exception in main

Live example


例2:

#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";
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

loud()
A()
~A()
~loud()
caught an int
caught an exception in main

Live example


Vla*_*cow 6

处理处理程序时,非静态成员可能尚未创建或已被销毁.

并且您的示例未演示函数try-block.当两个子对象都没有被销毁时,它是析构函数体内的一个try-block.

这是构造函数的function-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
}
Run Code Online (Sandbox Code Playgroud)