我在使用std::function<>
的论坛上听说会导致性能下降。这是真的吗?如果是真的,这是一个很大的性能下降吗?
答案 0 :(得分:74)
std:function
确实存在性能问题,每次使用时都必须考虑到这些问题。 std::function
的主要优势,即其类型擦除机制,并非免费提供,我们可能(但不一定必须)为此付出代价。
std::function
是一个包装可调用类型的模板类。但是,它不是在可调用类型本身上进行参数化,而是仅在其返回和参数类型上进行参数化。可调用类型仅在构造时知道,因此,std::function
不能具有此类型的预先声明的成员来保存给予其构造函数的对象的副本。
粗略地说(事实上,事情比这更复杂)std::function
只能保存指向传递给其构造函数的对象的指针,这会引发一个生命周期问题。如果指针指向生命周期小于std::function
对象生命周期的对象,则内部指针将变为悬空状态。为防止出现此问题,std::function
可能会通过调用operator new
(或自定义分配器)来复制堆上的对象。动态内存分配是人们最常引用的std::function
暗示的性能损失。
我最近写了一篇文章,其中包含更多细节,并解释了如何(以及在何处)避免支付内存分配的费用。
答案 1 :(得分:14)
您可以从推特的参考资料中找到相关信息:How much overhead does a call through boost::function incur?和Performance
这不会确定“是或否”来提升功能。考虑到程序的要求,性能下降可能是可以接受的。通常,程序的某些部分对性能不重要。即使这样,也可以接受。这只是你可以确定的事情。
对于标准库版本,标准仅定义了一个接口。完全由个人实现来使其工作。我想可以使用类似的boost函数实现。
答案 2 :(得分:11)
如果您在没有绑定任何参数(不分配堆空间)的情况下传递函数,这将非常依赖。
还取决于其他因素,但这是主要因素。
确实你需要比较一些东西,你不能简单地说它“减少了开销”,而不是完全不使用它,你需要将它与使用另一种传递函数的方法进行比较。如果您可以完全免除使用它,那么从一开始就不需要它
答案 3 :(得分:9)
首先,函数内部的开销变小;工作量越大,开销越小。
其次:与虚函数相比,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
#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; };
}
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.
所以,不要害怕。如果您的设计/可维护性可以通过优先std::function
而不是虚拟呼叫来改进,请尝试使用它们。就个人而言,我真的很喜欢不强制我的类的客户端上的接口和继承。