Evg*_*eny 38 c++ destructor exception object-lifetime c++14
我有以下代码:
#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(...) {}
}
Run Code Online (Sandbox Code Playgroud)
我看到他没有调用ok {3}的析构函数,输出是:
OK1 born
OK2 born
OK3 born
OK2 gone
OK1 gone
Run Code Online (Sandbox Code Playgroud)
这是C++ 14的预期行为吗?
编辑:
用gcc 6.3编译
P.W*_*P.W 23
根据标准,这种行为是错误的,这已经在问题的评论部分中提到过.这在" 异常处理 "一节中说明.
按照该缺陷报告在open-std.org,他们已经意识到,实现(GCC和锵)是错误的这一点,早在2015年9月28日.但提议的决议仅在2016年2月,编制者(GCC和Clang)尚未包含此修复.
拟议决议(2016年2月):
更改18.2 [except.ctor]第2段如下:
由于输入了try块,因此构造但尚未销毁的类类型的每个自动对象都会调用析构函数.如果在销毁临时语句或局部变量的过程中抛出异常(9.6.3 [stmt.return]),则还会调用返回对象(如果有)的析构函数.对象以完成构造的相反顺序销毁.[例:Run Code Online (Sandbox Code Playgroud)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处构建. - 末端的例子]
关于GCC错误报告的评论表明它显然是一个错误.
乔纳森威克利评论:
它现在是2013年所以,如果您的析构函数可以抛出,那么明智的做法就是不返回值.
另一个用户:
是的,我注意到了,而Clang也有一个针对他们的错误,这些错误已经萎缩多年.然而,这种行为是错误的.