【问题标题】:Destruction of return value on destructor exception析构函数异常时返回值的破坏
【发布时间】:2019-04-09 14:03:27
【问题描述】:

我有以下代码:

#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(...) {}
}

我看到他没有调用ok{3}的析构函数,输出是:

 OK1 born
 OK2 born
 OK3 born
 OK2 gone
 OK1 gone

这是 C++14 的预期行为吗?

编辑:

使用 gcc 6.3 编译

【问题讨论】:

  • 编译器和版本? cl v19.16.26926 不会发生
  • 我认为您应该将language-laywer 标签添加到问题中,并对其进行编辑以询问它在标准中是如何定义的。当然,包括您正在使用的确切编译器(和版本)。可能添加您的构建方式(使用优化标志等)。
  • "如果局部变量的析构函数或 return 语句中使用的临时变量的析构函数抛出异常,则函数返回的对象的析构函数也会被调用。(自 C ++14)" en.cppreference.com/w/cpp/language/throw
  • 这是defect #2176。该修复程序可能尚未进入 6.3。

标签: c++ exception c++14 destructor object-lifetime


【解决方案1】:

根据标准,这种行为是错误的,这已在问题的 cmets 部分中提到。 这在Exception handling 部分中有说明。

根据open-std.orgdefect reports,他们早在 2015 年 9 月 28 日就已经意识到实现(GCC 和 Clang)在这方面是错误的。 但提议的解决方案仅在 2016 年 2 月提出,编译器(GCC 和 Clang)尚未包含此修复程序。

提议的决议(2016 年 2 月):

将 18.2 [except.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 再次构造返回的对象。 ——结束示例]

GCCClang 中都针对此问题提交了错误。

GCC 错误报告中的 cmets 表明它显然是一个错误。

Jonathan Wakelycmets:

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

还有另一个用户:

是的,我注意到了,而且 Clang 也有一个针对他们的 bug,该 bug 已被搁置多年。然而,这种行为是错误的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-17
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多