首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我应该通过const-reference传递std::函数吗?

我应该通过const-reference传递std::函数吗?
EN

Stack Overflow用户
提问于 2013-08-22 02:58:24
回答 3查看 66.8K关注 0票数 165

假设我有一个函数,它接受一个std::function

代码语言:javascript
复制
void callFunction(std::function<void()> x)
{
    x();
}

我应该通过常量引用传递x吗?:

代码语言:javascript
复制
void callFunction(const std::function<void()>& x)
{
    x();
}

这个问题的答案会根据函数的作用而改变吗?例如,如果它是将std::function存储或初始化到成员变量中的类成员函数或构造函数。

EN

回答 3

Stack Overflow用户

发布于 2013-08-22 03:42:38

如果你想要性能,如果你在存储它,就通过值传递。

假设你有一个叫做“在UI线程中运行这个”的函数。

代码语言:javascript
复制
std::future<void> run_in_ui_thread( std::function<void()> )

它在"ui“线程中运行一些代码,然后在完成时向future发出信号。(在UI框架中很有用,UI线程是您应该处理UI元素的地方)

我们正在考虑两个签名:

代码语言:javascript
复制
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)

现在,我们可能会按如下方式使用它们:

代码语言:javascript
复制
run_in_ui_thread( [=]{
  // code goes here
} ).wait();

它将创建一个匿名闭包(一个λ),构造一个std::function,将其传递给run_in_ui_thread函数,然后等待它在主线程中完成运行。

在情况(A)中,直接从我们的lambda构造std::function,然后在run_in_ui_thread中使用它。λ被moved带入std::function,因此任何可移动的状态都可以有效地带入其中。

在第二种情况下,创建一个临时std::function,将lambda moved放入其中,然后在run_in_ui_thread中通过引用使用该临时std::function

到目前为止,一切都很好--他们两个的表现是一样的。除了run_in_ui_thread将要制作其函数参数的副本以发送到UI线程执行之外!(它将在使用它之前返回,因此它不能只使用对它的引用)。对于情况(A),我们只需将std::function move到其长期存储中。在情况(B)中,我们被迫复制std::function

该存储使按值传递更加优化。如果您可能正在存储std::function的副本,请通过值传递。除此之外,任何一种方法都是大致相等的:按值计算的唯一缺点是,如果您使用相同的笨重std::function,并让一个子方法一个接一个地使用它。除此之外,move将和const&一样高效。

现在,如果我们在std::function中有持久化状态,那么两者之间还有一些其他的差异。

假设std::function存储了一些带有operator() const的对象,但它也有一些mutable数据成员,并对其进行了修改(多么粗鲁!)。

std::function<> const&的情况下,修改的mutable数据成员将传播到函数调用之外。在std::function<>的情况下,他们不会。

这是一个相对奇怪的角落案例。

您希望像对待任何其他可能的重量级、廉价的可移动类型一样对待std::function。移动是便宜的,复制可能是昂贵的。

票数 87
EN

Stack Overflow用户

发布于 2013-08-22 03:11:31

如果您担心性能,并且没有定义虚拟成员函数,那么您很可能根本就不应该使用std::function

使函数器类型成为模板参数允许比std::function进行更大的优化,包括内联函数器逻辑。这些优化的效果很可能远远超过对如何通过std::function的复制与间接的担忧。

更快:

代码语言:javascript
复制
template<typename Functor>
void callFunction(Functor&& x)
{
    x();
}
票数 35
EN

Stack Overflow用户

发布于 2013-08-22 03:16:49

与通常在C++11中一样,通过值/引用/常量引用传递依赖于您如何处理参数。std::function也不例外。

通过值传递的允许您将参数移动到变量中(通常是类的成员变量):

代码语言:javascript
复制
struct Foo {
    Foo(Object o) : m_o(std::move(o)) {}

    Object m_o;
};

当你知道你的函数会移动它的参数时,这是最好的解决方案,这样你的用户就可以控制他们如何调用你的函数:

代码语言:javascript
复制
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

我相信你已经知道(非)常量引用的语义了,所以我不再赘述了。如果你需要我添加更多关于这方面的解释,请提出,我会更新的。

票数 30
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18365532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档