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