析构函数异常时返回值的破坏 [英] Destruction of return value on destructor exception

查看:141
本文介绍了析构函数异常时返回值的破坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

#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的析构函数没有被调用,输出为:

I see that he destructor of ok{3} is not called, the output is:

 OK1 born
 OK2 born
 OK3 born
 OK2 gone
 OK1 gone

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

编辑:

使用gcc 6.3编译

Compiling with gcc 6.3

推荐答案

按照标准,此行为是错误的,并且在问题的注释部分中已提及。
这在异常处理中的部分中进行了说明。

As per the standard this behavior is wrong and this has already been mentioned in the comments section of the question. This is stated in the section on Exception handling.

根据 open-std.org 的noreferrer>缺陷报告中,他们已经意识到实现(GCC和Clang)早在2015年9月28日就错了。
但是建议的解决方案仅在2016年2月才出现,编译器(GCC和Clang)尚未包括此修复程序。

As per the defect reports at open-std.org, they have been aware that implementations (GCC and Clang) were wrong about this as early as 2015-09-28. But the proposed resolution was only in February, 2016 and the compilers (GCC and Clang) have not yet included this fix.


建议的解决方案(2016年2月):

将18.2 [ctor除外]第2段更改如下:

自从进入try块以来,已构造但尚未销毁的每个类类型的自动对象都调用了析构函数。 如果在销毁针对返回语句的临时变量或局部变量的过程中引发异常(9.6.3 [stmt.return]),则会调用返回对象的析构函数(如果有)。对象按照其完成构造的相反顺序销毁。 [示例:

Change 18.2 [except.ctor] paragraph 2 as follows:
The destructor is invoked for each automatic object of class type constructed, but not yet destroyed, since the try block was entered. If an exception is thrown during the destruction of temporaries or local variables for a return statement (9.6.3 [stmt.return]), the destructor for the returned object (if any) is also invoked. The objects are destroyed in the reverse order of the completion of their construction. [Example:

  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处再次构造。 — —结束示例]

At #1, the returned object of type A is constructed. Then, the local variable b is destroyed (9.6 [stmt.jump]). Next, the local variable y is destroyed, causing stack unwinding, resulting in the destruction of the returned object, followed by the destruction of the local variable a. Finally, the returned object is constructed again at #2. —end example]

GCC C语

GCC错误报告中的注释表明它显然是错误。

The comments on the GCC bug report indicate that it is clearly a bug.

Jonathan Wakely 评论:


现在是2013年,因此明智的做法是,如果您的析构函数可以抛出异常,则不要按值返回。

It's now 2013 so the sensible thing to do is not return by value if your destructor can throw.

另一个用户:


是,我注意到,Clang也有一个针对他们的bug,该bug困扰了很多年。但是,该行为是错误的。

Yes, I noticed, and Clang has also had a bug filed against them which has languished for years. Nevertheless, the behavior is wrong.

这篇关于析构函数异常时返回值的破坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆