GCC 语句表达式中的执行顺序
Execution order in GCC statement expressions
我发现两个相似的语句之间有不同的执行顺序(唯一的区别是下面的语句多了一个;
)。析构函数顺序不同。 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>();;});
}
输出:
S(1)
S(2)
~S(1)
~S(2)
-----------------------------------
S(3)
S(4)
~S(4)
~S(3)
这不是标准的 C++。这是一个名为 statement expression 的 GCC 扩展。括号中的复合语句可以出现在允许表达式的地方。如果brace-enclosed块中的最后一条语句是一个表达式语句,那么这个表达式的值也是整个语句表达式的值;否则,语句表达式是 void
类型并且没有值。
你的第一个例子大致相当于
([](){ return S<1>(), S<2>(); })();
(这是创建后立即调用的 lambda)。有一个逗号表达式可以创建 S<1>
和 S<2>
临时值。 S<1>
被销毁,S<2>
在技术上被复制到 return 值 - 但该副本被删除。如果不是这个复制省略,你会看到
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
但是 (1)/(2) 对被省略,留下您在示例中观察到的序列。
在第二个例子中,大括号中的最后一个语句不是表达式,所以整个语句也没有值。大致相当于
([](){ S<3>(), S<4>(); return; })();
两个临时对象都在 lambda 中创建和销毁,并且适用通常的规则 - 临时对象以相反的构造顺序销毁。
我发现两个相似的语句之间有不同的执行顺序(唯一的区别是下面的语句多了一个;
)。析构函数顺序不同。 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>();;});
}
输出:
S(1)
S(2)
~S(1)
~S(2)
-----------------------------------
S(3)
S(4)
~S(4)
~S(3)
这不是标准的 C++。这是一个名为 statement expression 的 GCC 扩展。括号中的复合语句可以出现在允许表达式的地方。如果brace-enclosed块中的最后一条语句是一个表达式语句,那么这个表达式的值也是整个语句表达式的值;否则,语句表达式是 void
类型并且没有值。
你的第一个例子大致相当于
([](){ return S<1>(), S<2>(); })();
(这是创建后立即调用的 lambda)。有一个逗号表达式可以创建 S<1>
和 S<2>
临时值。 S<1>
被销毁,S<2>
在技术上被复制到 return 值 - 但该副本被删除。如果不是这个复制省略,你会看到
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
但是 (1)/(2) 对被省略,留下您在示例中观察到的序列。
在第二个例子中,大括号中的最后一个语句不是表达式,所以整个语句也没有值。大致相当于
([](){ S<3>(), S<4>(); return; })();
两个临时对象都在 lambda 中创建和销毁,并且适用通常的规则 - 临时对象以相反的构造顺序销毁。