函数 return 值是自动对象并因此保证被破坏吗?

Are function return values automatic objects and thus guaranteed to be destructed?

在 [except.ctor] 中,标准 (N4140) 保证:

...destructors are invoked for all automatic objects constructed since the try block was entered...

然而在下面的例子中,空output证明函数foo的return值没有被破坏,尽管它已经被构造。使用 g++ (5.2.1) 和 clang++ (3.6.2-1) 和选项 -O0 -fno-elide-constructors -std=c++14 编译。

struct A { ~A() { cout << "~A\n"; } };

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

A foo() {
  B b;
  return {};
}

int main() {
  try { foo(); }
  catch (...) { }
}

这是 g++ 和 clang++ 中的错误,还是函数 return 值不是 被认为是自动对象,还是 C++ 语言中的漏洞?

在 [stmt.return]、[expr.call] 或 [dcl.fct] 的 none 中,我已经能够找到 明确声明函数 return 值是否被视为自动 目的。我发现的最接近的提示是 6.3.3 p2:

...A return statement can involve the construction and copy or move of a temporary object...

和 5.2.2 p10:

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

这是一个错误,而这一次,MSVC 实际上是正确的:它打印“~A”。

我修改了你的代码,我认为现在从输出中我们可以看到 A 没有被破坏。

#include<iostream>

using namespace std;

struct A {
    ~A() { cout << "~A\n"; }
    A() { cout << "A()"; }
};

struct B {
    ~B() noexcept( false ) { cout << "~B\n"; throw(0); }
    B() { cout << "B()"; }
};

A foo() {
    B b;
    return;
}

int main() {
    try { foo(); }
    catch (...) {}
}

输出为:

B()A()~B

所以是的,这可能是一个错误。

函数 return 值被认为是临时值,return 值的构造在局部变量销毁之前排序。

不幸的是,这在标准中没有明确说明。有一个 open defect 描述了这个问题并提供了一些措辞来解决这个问题

[...] A return statement with an operand of type void shall be used only in a function whose return type is cv void. A return statement with any other operand shall be used only in a function whose return type is not cv void; the return statement initializes the object or reference to be returned by copy-initialization (8.5 [dcl.init]) from the operand. [...]

The copy-initialization of the returned entity is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables (6.6 [stmt.jump]) of the block enclosing the return statement.

由于函数 return 值是临时值,因此它们不在 post 开头的 destructors are invoked for all automatic objects 引号中。但是,[class.temporary]/3 表示:

[...] Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. [...]

所以我认为您可以认为这是 GCC 和 Clang 中的错误。

不要从析构函数中抛出 ;)