C++ 我应该通过常量引用传递 std::function 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18365532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should I pass an std::function by const-reference?
提问by Sven Adbring
Let's say I have a function which takes an std::function
:
假设我有一个函数,它需要一个std::function
:
void callFunction(std::function<void()> x)
{
x();
}
Should I pass x
by const-reference instead?:
我应该x
通过常量引用传递吗?:
void callFunction(const std::function<void()>& x)
{
x();
}
Does the answer to this question change depending on what the function does with it? For example if it is a class member function or constructor which stores or initializes the std::function
into a member variable.
这个问题的答案是否会根据函数的作用而改变?例如,如果它是一个类成员函数或构造函数,它将存储或初始化std::function
为成员变量。
回答by Yakk - Adam Nevraumont
If you want performance, pass by value if you are storing it.
如果您想要性能,则在存储它时按值传递。
Suppose you have a function called "run this in the UI thread".
假设您有一个名为“在 UI 线程中运行它”的函数。
std::future<void> run_in_ui_thread( std::function<void()> )
which runs some code in the "ui" thread, then signals the future
when done. (Useful in UI frameworks where the UI thread is where you are supposed to mess with UI elements)
它在“ui”线程中运行一些代码,然后future
在完成时发出信号。(在 UI 框架中很有用,其中 UI 线程是您应该弄乱 UI 元素的地方)
We have two signatures we are considering:
我们正在考虑两个签名:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Now, we are likely to use these as follows:
现在,我们可能会按如下方式使用这些:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
which will create an anonymous closure (a lambda), construct a std::function
out of it, pass it to the run_in_ui_thread
function, then wait for it to finish running in the main thread.
这将创建一个匿名闭包(一个 lambda),用std::function
它构造一个闭包,将它传递给run_in_ui_thread
函数,然后等待它在主线程中完成运行。
In case (A), the std::function
is directly constructed from our lambda, which is then used within the run_in_ui_thread
. The lambda is move
d into the std::function
, so any movable state is efficiently carried into it.
在情况 (A) 中,std::function
直接从我们的 lambda 构建,然后在run_in_ui_thread
. lambda 是move
d 到 中std::function
,因此任何可移动状态都有效地带入其中。
In the second case, a temporary std::function
is created, the lambda is move
d into it, then that temporary std::function
is used by reference within the run_in_ui_thread
.
在第二种情况下,std::function
创建一个临时对象,将 lambdamove
放入其中,然后std::function
在run_in_ui_thread
.
So far, so good -- the two of them perform identically. Except the run_in_ui_thread
is going to make a copy of its function argument to send to the ui thread to execute! (it will return before it is done with it, so it cannot just use a reference to it). For case (A), we simply move
the std::function
into its long-term storage. In case (B), we are forced to copy the std::function
.
到目前为止,一切都很好——他们两个的表现相同。除了将run_in_ui_thread
要复制其函数参数以发送到 ui 线程执行!(它会在完成之前返回,所以它不能只使用对它的引用)。对于情况(A),我们只是move
将std::function
其放入长期存储中。在情况 (B) 中,我们被迫复制std::function
.
That store makes passing by value more optimal. If there is any possibility you are storing a copy of the std::function
, pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function
and having one sub method after another use it. Barring that, a move
will be as efficient as a const&
.
该存储使传递值更加优化。如果您有可能存储 的副本std::function
,则按值传递。否则,任何一种方式都大致等效:按值的唯一缺点是,如果您使用相同的笨重std::function
方法并且一个又一个使用它的子方法。除此之外, amove
将与 a 一样有效const&
。
Now, there are some other differences between the two that mostly kick in if we have persistent state within the std::function
.
现在,如果我们在std::function
.
Assume that the std::function
stores some object with a operator() const
, but it also has some mutable
data members which it modifies (how rude!).
假设std::function
用 a 存储一些对象operator() const
,但它也有一些mutable
它修改的数据成员(多么粗鲁!)。
In the std::function<> const&
case, the mutable
data members modified will propagate out of the function call. In the std::function<>
case, they won't.
在这种std::function<> const&
情况下,mutable
修改的数据成员将传播到函数调用之外。在这种std::function<>
情况下,他们不会。
This is a relatively strange corner case.
这是一个相对奇怪的角落案例。
You want to treat std::function
like you would any other possibly heavy-weight, cheaply movable type. Moving is cheap, copying can be expensive.
您想像对待std::function
任何其他可能重量大、价格低廉的可移动类型一样对待。搬家很便宜,复印可能很贵。
回答by Ben Voigt
If you're worried about performance, and you aren't defining a virtual member function, then you most likely should not be using std::function
at all.
如果您担心性能,并且您没有定义虚拟成员函数,那么您很可能根本不应该使用它std::function
。
Making the functor type a template parameter permits greater optimization than std::function
, including inlining the functor logic. The effect of these optimizations is likely to greatly outweigh the copy-vs-indirection concerns about how to pass std::function
.
使函子类型成为模板参数允许比 更大的优化std::function
,包括内联函子逻辑。这些优化的效果可能大大超过复制与间接对如何传递的担忧std::function
。
Faster:
快点:
template<typename Functor>
void callFunction(Functor&& x)
{
x();
}
回答by syam
As usual in C++11, passing by value/reference/const-reference depends on what you do with your argument. std::function
is no different.
在 C++11 中,像往常一样,传递值/引用/常量引用取决于您对参数的处理方式。std::function
没有什么不同。
Passing by valueallows you to move the argument into a variable (typically a member variable of a class):
按值传递允许您将参数移动到变量中(通常是类的成员变量):
struct Foo {
Foo(Object o) : m_o(std::move(o)) {}
Object m_o;
};
When you know your function will move its argument, this is the best solution, this way your users can control how they call your function:
当你知道你的函数会移动它的参数时,这是最好的解决方案,这样你的用户可以控制他们如何调用你的函数:
Foo f1{Object()}; // move the temporary, followed by a move in the constructor
Foo f2{some_object}; // copy the object, followed by a move in the constructor
Foo f3{std::move(some_object)}; // move the object, followed by a move in the constructor
I believe you already know the semantics of (non)const-references so I won't belabor the point. If you need me to add more explanations about this, just ask and I'll update.
我相信你已经知道(非)const-references 的语义,所以我不会详细说明这一点。如果您需要我对此添加更多解释,请询问,我会更新。