C++ 通过移动捕获同一语句中使用的变量
编辑:标记为重复(某种程度上,没有未定义的行为,只是未指定),我被移动捕获lambda的人为复杂性所愚弄,这与此无关 我和我的同事发现,当我们在同一语句中通过常量引用使用变量后,试图通过move捕获变量时,GCC 6、7和Clang之间存在一个奇怪的差异。 一个简单的例子:C++ 通过移动捕获同一语句中使用的变量,c++,gcc,lambda,c++14,move-semantics,C++,Gcc,Lambda,C++14,Move Semantics,编辑:标记为重复(某种程度上,没有未定义的行为,只是未指定),我被移动捕获lambda的人为复杂性所愚弄,这与此无关 我和我的同事发现,当我们在同一语句中通过常量引用使用变量后,试图通过move捕获变量时,GCC 6、7和Clang之间存在一个奇怪的差异。 一个简单的例子: #include <iostream> #include <string> struct A { template <class F> void call (F f) {
#include <iostream>
#include <string>
struct A
{
template <class F> void call (F f)
{
f();
}
};
A test(const std::string& s)
{
std::cout << "in method: " << s << std::endl;
return {};
}
int main()
{
std::string s = "hello";
test(s).call([s = std::move(s)] { std::cout << "in lambda: " << s << std::endl;});
return 0;
}
GCC 7.2和Clang中的输出:
in method: hello
in lambda: hello
注意,使用两个语句,即autot=test;t、 调用(…)代码>给出了与GCC 6.3相同的(第二)结果。我们天真地期望第二个输出无处不在:它是GCC6错误、未定义的行为还是标准更改
对于信息,我们的“实际”案例是异步调用:test
是调用,struct A
是预期回调的结果。在C++14中,未指定是先计算test
还是先计算lambda表达式。但是,没有未定义的行为(假设test
不会使用从移动的字符串触发UB)
在C++17中,test(s)
总是在lambda之前进行评估。您的问题可以简化为类似于foo(i).call(i++)代码>。即未指明的结果。我认为这不是一个真正合适的重复;结果不是一个未定义的行为,但我假设了一个未指定的行为。事实上,它只是与序列点有关。然而,在玩Wandbox时,它似乎与标准版本无关,而是与GCC版本相关:GCC 6.3,使用--std=c++14或c++17:move是首先完成的,而GCC 7.1,使用这两种标准,move是在之后完成的。编辑:@FrédéricSamier看起来C++17的大部分新东西只在7中出现,这并不奇怪。
in method: hello
in lambda: hello