当使用lambda函数时,假设您决定复制变量(使用[=]表示法).如果您再也没有引用该变量,是否允许编译器将其移动到结果函数对象中?
编辑:例如,我写了一个片段来跨线程移动调用.这是一个样本.
extern "C" __declspec(dllexport) void parser_file_updated(Parser* p, const char* filename, int offset, int added) {
std::string file(filename);
p->make_call([=]() {
p->file_updated(std::move(file), offset, added);
});
}
Run Code Online (Sandbox Code Playgroud)
但显然,文件变量不需要经过lambda定义 - 事实上,lambda只被调用一次,所以我移动了副本.
sel*_*tze 12
如果您再也没有引用该变量,是否允许编译器将其移动到结果函数对象中?
不可以.允许编译器用移动替换副本的唯一情况是允许执行复制省略的完全相同的情况.这些情况包括按值返回本地对象或使用临时初始化对象.在这些情况下,允许编译器通过使源和目标成为相同的对象来消除副本.如果编译器由于某种原因无法执行此操作,则必须将源对象视为关于重载决策的rvalue,以便为目标对象选择适当的构造函数.但是,在您的情况下,file是Lvalue,并且上述情况均不适用.你必须使用明确的举动.
不幸的是,C++ 11没有"移动捕获"的语法.恕我直言,这是一种耻辱.但是std :: bind支持这个.应该可以将std :: bind与lambda表达式结合使用,如下所示:
void foo(char const* p) {
string s = p;
auto fun = bind([](string const& s){
...
},move(s));
fun();
}
Run Code Online (Sandbox Code Playgroud)
以便将字符串移动到函数对象中.
如果您只想调用此函数一次,并希望再次将该字符串移出函数对象,则可以使用非const引用:
void foo(char const* p) {
string s = p;
auto fun = bind([](string & s) {
some_other_func(move(s));
},move(s));
fun();
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您不想在此处使用bind但是让lambda对象的构造函数创建s的副本,则将该字符串移出函数对象需要mutable关键字:
void foo(char const* p) {
string s = p;
auto fun = [=]() mutable {
// ^^^^^^^
some_other_func(move(s));
};
fun();
}
Run Code Online (Sandbox Code Playgroud)
因为否则闭包类型的operator()函数将是const限定的,而这又是s一个const限定字符串.
在C++ 14中,lambda捕获子句变得更加灵活.我们现在可以写了
void foo(char const* p) {
string s = p;
auto fun = [s=move(s)]() mutable { // #1
some_other_func(move(s)); // #2
};
fun();
}
Run Code Online (Sandbox Code Playgroud)
其中#1将字符串值移动到lambda对象中,#2将字符串值移出(取决于如何some_other_func准确声明).