通过std :: function <bool(std :: string)> && callback(即作为右值移动)是否安全,会有什么效果?

时间:2018-08-29 10:30:09

标签: c++ c++11 move-semantics rvalue-reference

给出以下工作代码(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)即使用&&移动语义会更有效。 / p>

我从未真正使用过它,主要是因为我仍然不太了解它。

我的理解是:

void do_work(std::function<bool(std::string)> callback)-将获取我传入的lambda的副本(我认为这是一个右值)。

void do_work(std::function<bool(std::string)> callback)-将移动我传入的lambda,因为它是一个右值。

我对rvalue的粗略想法是任何临时变量。

问题:

  1. 我不是100%清楚的是,我写的正确吗?因此使用&&是安全的。两者似乎都可以。

  2. 如果&&方法不是传递像这样的lambda,是否也起作用?

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 :(得分:3)

如果参数定义为右值引用,则必须传递临时值或将左值强制转换为右值,例如override fun onUpgrade(db: SQLiteDatabase, oldV: Int, newV: Int) { if (oldVersion < 2) { upgradeVersion2(db) } if (oldVersion < 3) { upgradeVersion3(db) } if (oldVersion < 4) { upgradeVersion4(db) } }

rvalue-references的语义是,调用者应期望掠夺传递的参数,使其成为有效但任意的,这主要是无用的。

但是,尽管具有掠夺许可,但接收右值引用的函数却没有任何掠夺义务。而且如果它没有明确地这样做,例如通过传递该许可证,那么它就不会通过,并且没有什么特别的事情发生。

您的代码就是这种情况。

虽然我会禁止使用std::move()词汇表,但无论使用与否实际上并没有太大的不同。

答案 1 :(得分:1)

在这种情况下,无论您是通过值传递还是通过rval ref传递,都必须创建一个临时的std :: function,这是因为lambda并不是真正的std :: function。无论如何,都应在分配之前移动std :: function,以避免产生不必要的副本。
我建议在这种情况下按值传递,因为这样做比较灵活,并且如果传递lambda,则不会造成任何危害,因为std :: function通常会在适当的位置构造(因此临时不会移入函数;通常可以(通常会)忽略此移入)。