传递 std::function<bool(std::string)> &&callback(即作为右值移动)是否安全,效果如何?
Is it safe to pass std::function<bool(std::string)> &&callback (i.e. as a rvalue move) and what is the effect?
给定以下工作代码 (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)
- 将获取我传入的 lambda 的副本(我认为这是一个右值)。
void do_work(std::function<bool(std::string)> callback)
- 将移动我传入的 lambda,因为它是一个右值。
我对右值的粗略理解是任何临时变量。
问题:
我不是100%清楚的是,我写的对吗?因此使用 &&
安全吗?两者似乎都有效。
如果不传递这样的 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));
如果参数定义为右值引用,则必须传递临时值或将左值转换为右值,如 std::move()
.
右值引用的语义是调用者应该期望传递的参数被掠夺,使其有效但任意,意味着大部分无用。
但是接收右值引用的函数,尽管有掠夺许可,但没有任何掠夺的义务。如果它没有明确这样做,例如通过该许可证,那么它就不会通过,也不会发生任何特殊情况。
你的代码就是这种情况。
虽然我会在我的词汇表中禁止使用 std::bind
,但使用与否实际上没有任何显着差异。
在这种情况下,无论您是按值还是按 rval ref 传递,都必须创建临时 std::function,这是因为 lambda 并不是真正的 std::function。在任何情况下,您都应该在分配之前移动 std::function,以避免进行不必要的复制。
我建议在这种情况下按值传递,因为这更灵活一点,如果你传递的是 lambda,那么它不会造成任何伤害,因为 std::function 通常会在适当的位置构造(所以temporary 不会被移动到函数中;这个移动可以而且通常会被省略)。
给定以下工作代码 (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)
- 将获取我传入的 lambda 的副本(我认为这是一个右值)。
void do_work(std::function<bool(std::string)> callback)
- 将移动我传入的 lambda,因为它是一个右值。
我对右值的粗略理解是任何临时变量。
问题:
我不是100%清楚的是,我写的对吗?因此使用
&&
安全吗?两者似乎都有效。如果不传递这样的 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));
如果参数定义为右值引用,则必须传递临时值或将左值转换为右值,如 std::move()
.
右值引用的语义是调用者应该期望传递的参数被掠夺,使其有效但任意,意味着大部分无用。
但是接收右值引用的函数,尽管有掠夺许可,但没有任何掠夺的义务。如果它没有明确这样做,例如通过该许可证,那么它就不会通过,也不会发生任何特殊情况。
你的代码就是这种情况。
虽然我会在我的词汇表中禁止使用 std::bind
,但使用与否实际上没有任何显着差异。
在这种情况下,无论您是按值还是按 rval ref 传递,都必须创建临时 std::function,这是因为 lambda 并不是真正的 std::function。在任何情况下,您都应该在分配之前移动 std::function,以避免进行不必要的复制。
我建议在这种情况下按值传递,因为这更灵活一点,如果你传递的是 lambda,那么它不会造成任何伤害,因为 std::function 通常会在适当的位置构造(所以temporary 不会被移动到函数中;这个移动可以而且通常会被省略)。