C++ 析构函数异常时返回值的销毁

C++ 析构函数异常时返回值的销毁,c++,exception,c++14,destructor,object-lifetime,C++,Exception,C++14,Destructor,Object Lifetime,我有以下代码: #include <stdexcept> #include <iostream> struct ok { int _n; ok(int n) : _n(n) { std::cerr << "OK" << n << " born" << std::endl; } ~ok() { std::cerr << "OK" << _n << " gone"

我有以下代码:

#include <stdexcept>
#include <iostream>

struct ok {
    int _n;
    ok(int n) : _n(n) { std::cerr << "OK" << n << " born" << std::endl; }
    ~ok() {  std::cerr << "OK" << _n << " gone" << std::endl; }
};

struct problematic {
    ~problematic() noexcept(false) { throw std::logic_error("d-tor exception"); }
};

ok boo() {
    ok ok1{1};
    problematic p;
    ok ok2{2};
    return ok{3}; // Only constructor is called...
}

int main(int argc, char **argv) {
    try {boo();} catch(...) {}
}
这是C++14的预期行为吗?

编辑:


按照标准使用gcc 6.3编译此行为是错误的,这已在问题的评论部分提到。 这一点在关于的章节中有所说明

根据at,他们早在2015年9月28日就意识到实施(GCC和Clang)在这方面是错误的。 但提议的解决方案只是在2016年2月提出的,而且编译器(GCC和Clang)还没有包括此修复

拟议决议(2016年2月):

将第18.2款[除ctor外]第2款更改如下:
对于自输入try块以来已构造但尚未销毁的类类型的每个自动对象,将调用析构函数如果在为return语句(9.6.3[stmt.return])销毁临时变量或局部变量期间引发异常,则还将调用返回对象(如果有)的析构函数。对象将按与其构造完成相反的顺序销毁。[示例:

  struct A { };

  struct Y { ~Y() noexcept(false) { throw 0; } };

  A f() {
    try {
      A a;
      Y y;
      A b;
      return {};   // #1
    } catch (...) {
    }
    return {};     // #2
  }
在#1,构造类型为A的返回对象,然后销毁局部变量b(9.6[stmt.jump]).接下来,局部变量y被销毁,导致堆栈展开,导致返回对象被销毁,接着局部变量a被销毁。最后,返回对象在#2处再次构造。-结束示例]

在和中都存在针对此问题的bug

GCC错误报告上的评论表明,它显然是一个错误

评论:

现在是2013年,所以如果析构函数可以抛出,明智的做法是不按值返回

和另一个用户:

是的,我注意到了,而且Clang也有一个针对他们的漏洞,这个漏洞已经存在多年了。然而,这种行为是错误的


编译器和版本?cl v19.16.26926不会出现这种情况。我认为您应该在问题中添加
language laywer
标记,并对其进行编辑,询问在标准中如何定义它。当然,包括您正在使用的确切编译器(和版本)。可能添加您的构建方式(使用优化标志等)??“如果从return语句中使用的局部变量或临时变量的析构函数引发异常,也会调用从函数返回的对象的析构函数。(因为C++14)”这是错误的。修复程序可能无法将其写入6.3。
  struct A { };

  struct Y { ~Y() noexcept(false) { throw 0; } };

  A f() {
    try {
      A a;
      Y y;
      A b;
      return {};   // #1
    } catch (...) {
    }
    return {};     // #2
  }