Безопасно ли передавать обратный вызов std :: function <bool (std :: string)> && (т.е. как перемещение по значению) и каков эффект? - PullRequest
0 голосов
/ 29 августа 2018

С учетом следующего рабочего кода (main.cpp):

#include <functional>
#include <iostream>

struct worker
{
   std::function<bool(std::string)> m_callback;
   void do_work(std::function<bool(std::string)> callback) // <--- this line
   {
      m_callback = std::bind(callback, std::placeholders::_1);
      callback("hello world!\n");
   }
};


// pretty boring class - a cut down of my actual class
struct helper
{
   worker the_worker;
   bool work_callback(std::string str)
   {
      std::cout << str << std::endl;
      return false;
   }
};

int main()
{
   helper the_helper;
   the_helper.the_worker.do_work( [&](std::string data){ return the_helper.work_callback(data); });
}

Составлено с: -std=c++11 -O2 -Wall -Wextra -pedantic-errors -O2 main.cpp

У меня есть комментарий к рассматриваемой строке (<-- this line - вокруг строки 7), где я думаю, что было бы более эффективно использовать: void do_work(std::function<bool(std::string)>&& callback), т. Е. С использованием семантики перемещения &&.

Я никогда этим не пользовался, в основном потому, что до сих пор не совсем понимаю.

Мое понимание таково:

void do_work(std::function<bool(std::string)> callback) - возьмет копию лямбды, которую я передаю (я думаю, это значение).

void do_work(std::function<bool(std::string)> callback) - переместит лямбду, которую я передаю, потому что это значение.

Мое грубое представление о rvalue - любая временная переменная.

Вопросы:

  1. Что мне не ясно на 100%, так это то, что я написал правильно? и поэтому безопасно ли использовать &&. Оба, кажется, работают.

  2. Этот метод && также работает, если вместо передачи лямбда-выражения, как это:

the_helper.the_worker.do_work( [&](std::string data){ return the_helper.work_callback(data); });

переходим в std :: bind (...):

the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1));

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

В этом случае, независимо от того, передаете ли вы по значению или по rval ref временную std :: function, необходимо создать, потому что лямбда на самом деле не является std :: function. В любом случае вам следует передвинуть функцию std :: перед назначением, чтобы избежать создания ненужной копии.
В этом случае я бы рекомендовал передавать по значению, поскольку это немного более гибко, и если вы передаете лямбда-выражения, то это не причинит никакого вреда, так как функция std :: обычно создается на месте (поэтому временная не будет перемещен в функцию; этот шаг может быть и обычно будет исключен).

0 голосов
/ 29 августа 2018

Если параметр определен как rvalue-reference, вы должны передать временное значение или привести lvalue к rvalue, как с std::move().

И семантика ссылок на rvalue заключается в том, что вызывающая сторона должна ожидать, что переданный аргумент будет разграблен, что сделает его действительным, но произвольным, что означает в основном бесполезный.

Но функция, получающая ссылку на rvalue, несмотря на то, что у нее есть лицензия для хищения , не обязана грабить . И если это явно не делается, например, путем передачи этой лицензии, то это не происходит, и ничего особенного не происходит.

Ваш код такой случай.

Хотя я бы запретил std::bind из своего словаря, использование его или нет на самом деле не имеет существенного значения.

...