C++ std::function 的性能开销是多少?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5057382/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:17:05  来源:igfitidea点击:

What is the performance overhead of std::function?

c++booststd

提问by Cassio Neri

I heard on a forum using std::function<>causes performance drop. Is it true? If true, is it a big performance drop?

我在论坛上听说使用std::function<>原因导致性能下降。这是真的吗?如果为真,是不是性能下降很大?

采纳答案by UncleBens

You can find information from the boost's reference materials: How much overhead does a call through boost::function incur?and Performance

您可以从 boost 的参考资料中找到信息:通过 boost::function 调用会产生多少开销?性能

This doesn't determine "yes or no" to boost function. The performance drop may be well acceptable given program's requirements. More often than not, parts of a program are not performance-critical. And even then it may be acceptable. This is only something you can determine.

这并不能确定“是或否”以增强功能。鉴于程序的要求,性能下降可能是可以接受的。通常情况下,程序的某些部分不是性能关键的。即便如此,它也可能是可以接受的。这只是您可以确定的。

As to the standard library version, the standard only defines an interface. It is entirely up to individual implementations to make it work. I suppose a similar implementation to boost's function would be used.

对于标准库版本,标准只定义了一个接口。使其工作完全取决于个人实现。我想将使用与 boost 函数类似的实现。

回答by Cassio Neri

There are, indeed, performance issues with std:functionthat must be taken into account whenever using it. The main strength of std::function, namely, its type-erasure mechanism, does not come for free, and we might (but not necessarily must) pay a price for that.

实际上,std:function无论何时使用它,都必须考虑到性能问题。的主要优势std::function,即它的类型擦除机制,并不是免费的,我们可能(但不一定必须)为此付出代价。

std::functionis a template class that wraps callable types. However, it is not parametrized on the callable type itself but only on its return and argument types. The callable type is known only at construction time and, therefore, std::functioncannot have a pre-declared member of this type to hold a copy of the object given to its constructor.

std::function是包装可调用类型的模板类。但是,它不是在可调用类型本身上参数化的,而只是在其返回和参数类型上参数化。可调用类型仅在构造时才知道,因此std::function不能有此类型的预先声明的成员来保存提供给其构造函数的对象的副本。

Roughly speaking (actually, things are more complicated than that) std::functioncan hold only a pointer to the object passed to its constructor, and this raises a lifetime issue. If the pointer points to an object whose lifetime is smaller than that of the std::functionobject, then the inner pointer will become dangling. To prevent this problem std::functionmight make a copy of the object on the heap through a call to operator new(or a custom allocator). The dynamic memory allocation is what people refer the most as a performance penalty implied by std::function.

粗略地说(实际上,事情比这更复杂)std::function只能保存一个指向传递给其构造函数的对象的指针,这会引发生命周期问题。如果指针指向的对象的生命周期小于该对象的生命周期std::function,则内部指针将变为悬空。为防止此问题,std::function可能会通过调用operator new(或自定义分配器)在堆上复制对象。人们最常将动态内存分配称为std::function.

I have recently written an article with more details and that explains how (and where) one can avoid paying the price of a memory allocation.

我最近写了一篇更详细的文章,解释了如何(以及在​​哪里)避免支付内存分配的代价。

Efficient Use of Lambda Expressions and std::function

高效使用 Lambda 表达式和 std::function

回答by lurscher

This depends strongly if you are passing the function without binding any argument (does not allocate heap space) or not.

这在很大程度上取决于您是否在不绑定任何参数的情况下传递函数(不分配堆空间)。

Also depends on other factors, but this is the main one.

还取决于其他因素,但这是主要因素。

It is true that you need something to compare against, you can't just simply say that it 'reduces overhead' compared to not using it at all, you need to compare it to using an alternative way to passing a function. And if you can just dispense of using it at all then it was not needed from the beginning

确实,您需要比较某些东西,您不能简单地说它与根本不使用它相比“减少了开销”,您需要将它与使用传递函数的替代方法进行比较。如果你可以完全不使用它,那么从一开始就不需要它

回答by Sebastian Mach

Firstly, the overhead gets smaller with the inside of the function; the higher the workload, the smaller the overhead.

首先,随着函数内部的开销越来越小;工作负载越高,开销越小。

Secondly: g++ 4.5 does not show any difference compared to virtual functions:

其次:g++ 4.5 与虚函数相比没有任何区别:

main.cc

主文件

#include <functional>
#include <iostream>

// Interface for virtual function test.
struct Virtual {
    virtual ~Virtual() {}
    virtual int operator() () const = 0;
};

// Factory functions to steal g++ the insight and prevent some optimizations.
Virtual *create_virt();
std::function<int ()> create_fun();
std::function<int ()> create_fun_with_state();

// The test. Generates actual output to prevent some optimizations.
template <typename T>
int test (T const& fun) {
    int ret = 0;
    for (int i=0; i<1024*1024*1024; ++i) {
        ret += fun();
    }    
    return ret;
}

// Executing the tests and outputting their values to prevent some optimizations.
int main () {
    {
        const clock_t start = clock();
        std::cout << test(*create_virt()) << '\n';
        const double secs = (clock()-start) / double(CLOCKS_PER_SEC);
        std::cout << "virtual: " << secs << " secs.\n";
    }
    {
        const clock_t start = clock();
        std::cout << test(create_fun()) << '\n';
        const double secs = (clock()-start) / double(CLOCKS_PER_SEC);
        std::cout << "std::function: " << secs << " secs.\n";
    }
    {
        const clock_t start = clock();
        std::cout << test(create_fun_with_state()) << '\n';
        const double secs = (clock()-start) / double(CLOCKS_PER_SEC);
        std::cout << "std::function with bindings: " << secs << " secs.\n";
    }
}

impl.cc

实现.cc

#include <functional>

struct Virtual {
    virtual ~Virtual() {}
    virtual int  operator() () const = 0;
};
struct Impl : Virtual {
    virtual ~Impl() {}
    virtual int  operator() () const { return 1; }
};

Virtual *create_virt() { return new Impl; }

std::function<int ()> create_fun() { 
    return  []() { return 1; };
}

std::function<int ()> create_fun_with_state() { 
    int x,y,z;
    return  [=]() { return 1; };
}

Output of g++ --std=c++0x -O3 impl.cc main.cc && ./a.out:

的输出g++ --std=c++0x -O3 impl.cc main.cc && ./a.out

1073741824
virtual: 2.9 secs.
1073741824
std::function: 2.9 secs.
1073741824
std::function with bindings: 2.9 secs.

So, fear not. If your design/maintainability can improve from prefering std::functionover virtual calls, try them. Personally, I really like the idea of not forcing interfaces and inheritance on clients of my classes.

所以,不要害怕。如果您的设计/可维护性可以通过优先std::function于虚拟调用来提高,请尝试它们。就我个人而言,我真的很喜欢不要在我的类的客户端上强制使用接口和继承的想法。