简体   繁体   中英

Is it safe to pass std::function<bool(std::string)> &&callback (i.e. as a rvalue move) and what is the effect?

Given the following working code (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); });
}

Compiled with: -std=c++11 -O2 -Wall -Wextra -pedantic-errors -O2 main.cpp

I have comment the line in question ( <-- this line - around line 7), where I think it would be more efficient to use: void do_work(std::function<bool(std::string)>&& callback) ie using the && move semantic.

I have never really used this, mostly because I still don't quite understand it.

My understanding is this:

void do_work(std::function<bool(std::string)> callback) - will take a copy of the lambda that I pass in (which is an rvalue I think).

void do_work(std::function<bool(std::string)> callback) - will move the lambda that I pass in because it is an rvalue.

My crude idea of an rvalue is any temporary variable.

Questions:

  1. What I am not 100% clear about is, is what I wrote correct? and therefore is it safe to use && . Both seem to work.

  2. Does this && method also work if instead of passing a lambda like this:

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

we pass in std::bind(...):

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

If the parameter is defined as an rvalue-reference, you must pass a temporary or cast an lvalue to an rvalue, like with std::move() .

And the semantics of rvalue-references are that the caller should expect the passed argument to be plundered, rendering it valid but arbitrary, meaning mostly useless.

But the function receiving an rvalue-reference, despite having license to plunder , does not have any obligation to plunder . And if it doesn't explicitly do so, for example by passing that license on, then it doesn't come to pass, and nothing special happens.

Your code is such a case.

While I would ban std::bind from my vocabulary, using it or not doesn't actually make any significant difference.

In this case regardless of whether you pass by value or by rval ref a temporary std::function will have to be created, that's because a lambda is not really a std::function. In any case, you should move the std::function before assigning, to avoid making an unnecessary copy.
I'd recommend passing by value in this case, as this is a bit more flexible, and if you are passing lambdas, then it does not cause any harm, as the std::function will usually be constructed in place (so the temporary will not be moved into the function; this move can, and usually will, be elided).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM