在同一命令中使用变量时移至 lambda
Move to lambda while using the variable in the same command
让我们考虑以下旨在毁灭世界的结构。
#include <iostream>
#include <vector>
struct SkyNet {
std::vector<int> terminators;
SkyNet() = default;
SkyNet(SkyNet&& that)
{
printf("Move construct\n");
this->terminators = std::move(that.terminators);
}
};
class Apocalypse {
public:
template <typename Lambda>
void run(Lambda lambda) {
lambda();
}
};
Apocalypse create_apocalypse(const SkyNet& net) {
std::cout << "Create: " << net.terminators.size() << " terminators\n";
return Apocalypse();
}
(请原谅这些结构的糟糕设计和其他缺陷。创建它只是为了演示特定问题。)
然后我们有简单的 main:
int main()
{
SkyNet net;
net.terminators.push_back(10);
create_apocalypse(net)
.run([net = std::move(net)] {
std::cout << "Lambda: " << net.terminators.size() << " terminators\n";
});
return 0;
}
输出:
Move construct
Create: 0 terminators
Lambda: 1 terminators
这意味着 run
函数的参数将在调用链接其他事件的 create_apocalypse
函数之前创建(评估?)。这是正确的吗?这是一个通用规则,即表达式的所有参数(不仅是第一个函数的参数)首先被求值,然后才调用函数吗?
当您创建 lambda 时,您正在创建一个匿名对象。当你定义闭包时,你就是在定义它的构造函数和成员。
所以这相当于:
crete_apocalypse(net).run(MyLambda{std::move(net)});
这在语义上等同于
run(create_apocalypse(net), MyLambda{std::move(net)});
由于标准未指定函数参数的计算顺序,因此可以自由选择实现。换句话说,它可以选择首先选择 create_apocalypse(net)
然后按照您的预期去做,或者它可以反过来(在您的情况下这样做)并首先构建 MyLambda
,从而移动 net
,一旦到达 create_apocalypse()
,它就已经移动了。
当它真正重要时,您不应该依赖于您为特定编译器获得的行为。避免它并保持正确性的方法是这样写:
auto a = create_apocalypse(net);
a.run([net = std::move(net)] { /* ... */ });
让我们考虑以下旨在毁灭世界的结构。
#include <iostream>
#include <vector>
struct SkyNet {
std::vector<int> terminators;
SkyNet() = default;
SkyNet(SkyNet&& that)
{
printf("Move construct\n");
this->terminators = std::move(that.terminators);
}
};
class Apocalypse {
public:
template <typename Lambda>
void run(Lambda lambda) {
lambda();
}
};
Apocalypse create_apocalypse(const SkyNet& net) {
std::cout << "Create: " << net.terminators.size() << " terminators\n";
return Apocalypse();
}
(请原谅这些结构的糟糕设计和其他缺陷。创建它只是为了演示特定问题。)
然后我们有简单的 main:
int main()
{
SkyNet net;
net.terminators.push_back(10);
create_apocalypse(net)
.run([net = std::move(net)] {
std::cout << "Lambda: " << net.terminators.size() << " terminators\n";
});
return 0;
}
输出:
Move construct
Create: 0 terminators
Lambda: 1 terminators
这意味着 run
函数的参数将在调用链接其他事件的 create_apocalypse
函数之前创建(评估?)。这是正确的吗?这是一个通用规则,即表达式的所有参数(不仅是第一个函数的参数)首先被求值,然后才调用函数吗?
当您创建 lambda 时,您正在创建一个匿名对象。当你定义闭包时,你就是在定义它的构造函数和成员。
所以这相当于:
crete_apocalypse(net).run(MyLambda{std::move(net)});
这在语义上等同于
run(create_apocalypse(net), MyLambda{std::move(net)});
由于标准未指定函数参数的计算顺序,因此可以自由选择实现。换句话说,它可以选择首先选择 create_apocalypse(net)
然后按照您的预期去做,或者它可以反过来(在您的情况下这样做)并首先构建 MyLambda
,从而移动 net
,一旦到达 create_apocalypse()
,它就已经移动了。
当它真正重要时,您不应该依赖于您为特定编译器获得的行为。避免它并保持正确性的方法是这样写:
auto a = create_apocalypse(net);
a.run([net = std::move(net)] { /* ... */ });