Переезд с лямбдами - PullRequest
       4

Переезд с лямбдами

16 голосов
/ 13 декабря 2010

При использовании лямбда-функций допустим, что вы решили скопировать переменную (с пометкой [=]). Если вы никогда не ссылаетесь на эту переменную снова, разрешено ли компилятору переместить ее в результирующий объект функции?

Edit: например, я написал фрагмент для перемещения вызовов между потоками. Вот пример, который делает это.

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);
     });
}

Но ясно, что файловая переменная не должна жить после определения лямбды - и действительно, лямбда вызывается только один раз, поэтому я переместил копию.

1 Ответ

12 голосов
/ 18 декабря 2010

Если вы никогда больше не ссылаетесь на эту переменную, разрешено ли компилятору переместить ее в результирующий объект функции?

Нет.Единственной ситуацией, когда компилятору разрешено заменять копию ходом, являются те же самые ситуации, когда ему разрешено выполнять удаление копии.Эти ситуации включают в себя возврат локального объекта по значению или инициализацию объекта временным.В этих случаях компилятору разрешается исключить копию, создавая источник и нацеливаясь на один и тот же объект.Если компилятор не может сделать это по какой-либо причине, он должен рассматривать исходный объект как значение по отношению к разрешению перегрузки для выбора соответствующего конструктора для целевого объекта.В вашем случае, однако, файл является Lvalue, и ни один из вышеперечисленных случаев не применяется.Вам придется использовать явное перемещение.

К сожалению, в C ++ 11 нет синтаксиса для «захвата хода».ИМХО, это позор.Но std :: bind поддерживает это.Должна быть возможность комбинировать std :: bind с лямбда-выражением, например:

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();
}

Обратите внимание, что если вы не хотите использовать здесь привязку, но разрешите лямбдуконструктор объекта создает копию s, перемещение строки из объекта функции требует ключевого слова mutable:

void foo(char const* p) {
   string s = p;
   auto fun = [=]() mutable {
      //            ^^^^^^^
      some_other_func(move(s));
   };
   fun();
}

, потому что в противном случае функция operator () типа замыкания будет квалифицирована как const, что, в свою очередь, составляет s константно-квалифицированная строка.

В C ++ 14 предложение захвата лямбды стало немного более гибким.Теперь мы можем написать

void foo(char const* p) {
   string s = p;
   auto fun = [s=move(s)]() mutable { // #1
      some_other_func(move(s));       // #2
   };
   fun();
}

, где # 1 перемещает строковое значение в лямбда-объект, а # 2 перемещает строковое значение наружу (в зависимости от того, как some_other_func объявлено точно).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...