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

时间:2014-08-02 10:36:52

标签: c++ c++11 language-lawyer

来自相关的c ++标准部分:

  

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

例如。

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

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

3 个答案:

答案 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中抛出异常:所有子对象都将被销毁。


示例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";
    }
}

输出:

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";
    }
}

输出:

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

Live example

答案 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块中时,无法确定异常的来源以及初始化/销毁哪个对象。