假设使用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);
     });
}

但很明显,文件变量不需要超出lambda定义-实际上,lambda仅被调用一次,因此我移动了副本。

最佳答案



否。唯一允许编译器用移动替换副本的情况是完全相同的情况,它允许执行复制省略。这些情况包括按值返回本地对象或使用临时对象初始化对象。在这些情况下,允许编译器通过使源和目标成为同一对象来删除副本。如果编译器由于某种原因无法执行此操作,则必须将源对象视为重载解析的右值,以便为目标对象选择适当的构造函数。但是,在您的情况下,文件是左值,并且上述情况均不适用。您将必须使用显式移动。

不幸的是,C++ 11没有“移动捕获”的语法。恕我直言,真是可惜。但是std::bind支持这一点。应该可以将std::bind与一个lambda表达式结合起来,如下所示:

void foo(char const* p) {
   string s = p;
   auto fun = bind([](string const& s){
      ...
   },move(s));
   fun();
}

以便将字符串移到函数对象中。

如果您打算只调用一次此函数,并且想将字符串再次从函数对象中移出,则可以使用非常量引用:
void foo(char const* p) {
   string s = p;
   auto fun = bind([](string & s) {
      some_other_func(move(s));
   },move(s));
   fun();
}

请注意,如果您不想在此处使用bind,而是让lambda对象的构造函数创建s的副本,则将字符串移出函数对象需要使用mutable关键字:
void foo(char const* p) {
   string s = p;
   auto fun = [=]() mutable {
      //            ^^^^^^^
      some_other_func(move(s));
   };
   fun();
}

因为否则封闭类型的operator()函数将是const限定的,这又使s成为const限定的字符串。

在C++ 14中,lambda capture子句变得更加灵活。我们现在可以写
void foo(char const* p) {
   string s = p;
   auto fun = [s=move(s)]() mutable { // #1
      some_other_func(move(s));       // #2
   };
   fun();
}

其中#1将字符串值移到lambda对象中,而#2将字符串值移出(具体取决于some_other_func的声明方式)。

关于c++ - 与lambdas一起移动,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4433109/

10-16 04:51