GCC 语句表达式中的执行顺序

edd*_*kuo 2 c++ gcc gcc-statement-expression

我发现两个相似的语句之间有不同的执行顺序(唯一的区别是下面有一个额外的;)。析构函数顺序不同。C++ 是否有相应的规范,或者它只是一种未指定的行为?

环境:GCC10

#include <iostream>

template <int num>
struct S {
  S() {std::cout << "S(" << num << ")\n"; }
  ~S() {std::cout << "~S(" << num << ")\n"; }
};

int main() {
  ({S<1>(), S<2>();});
  std::cout << "-----------------------------------\n";
  ({S<3>(), S<4>();;});
}

Run Code Online (Sandbox Code Playgroud)

输出:

S(1)
S(2)
~S(1)
~S(2)
-----------------------------------
S(3)
S(4)
~S(4)
~S(3)
Run Code Online (Sandbox Code Playgroud)

Igo*_*nik 6

这不是标准的 C++。这是称为语句表达式的 GCC 扩展。括号中的复合语句可以出现在允许使用表达式的地方。如果大括号括起来的块中的最后一条语句是表达式语句,则该表达式的值也是整个语句表达式的值;否则,语句表达式为类型void且没有值。

你的第一个例子大致相当于

([](){ return S<1>(), S<2>(); })();
Run Code Online (Sandbox Code Playgroud)

(这是一个创建然后立即调用的 lambda)。有一个逗号表达式可以创建S<1>S<2>临时。S<1>被销毁,S<2>从技术上讲,被复制到返回值 - 但该副本被省略。如果不是这个复制省略,你会看到

S<1>()
S<2>()
S<2>(S<2>&&)  // (1) move constructor
~S<2>()  // (2) the original temporary is destroyed
~S<1>()
~S<2>()  // the copy is destroyed outside of the lambda
Run Code Online (Sandbox Code Playgroud)

但是 (1)/(2) 对被省略,留下您在示例中观察到的序列。

在第二个示例中,大括号内的最后一条语句不是表达式,因此整个内容也没有值。它大致相当于

([](){ S<3>(), S<4>(); return; })();
Run Code Online (Sandbox Code Playgroud)

两个临时对象都在 lambda 中创建和销毁,通常的规则适用 - 临时对象以与构造相反的顺序销毁。