【发布时间】:2009-05-11 01:58:07
【问题描述】:
如果我有一个没有状态的仿函数类,但我使用 new 从堆中创建它,那么典型的编译器是否足够聪明,可以完全优化创建开销?
这个问题是在制作一堆无状态函子时出现的。如果它们被分配在堆栈上,它们的 0 状态类主体是否意味着堆栈真的根本没有改变?看来它必须以防您稍后获取仿函数实例的地址。 堆分配也一样。
在这种情况下,仿函数总是在创建过程中添加(微不足道但非零)开销。但也许编译器可以看到该地址是否被使用,如果没有,它可以消除堆栈分配。 (或者,它甚至可以消除堆分配吗?)
但是作为临时创建的函子怎么样?
#include <iostream>
struct GTfunctor
{
inline bool operator()(int a, int b) {return a>b; }
};
int main()
{
GTfunctor* f= new GTfunctor;
GTfunctor g;
std::cout<< (*f)(2,1) << std::endl;
std::cout<< g(2,1) << std::endl;
std::cout<< GTfunctor()(2,1) << std::endl;
delete f;
}
所以在上面的具体例子中,三行分别以三种不同的方式调用同一个函子。在此示例中,这些方式之间是否存在效率差异?或者编译器是否能够将每一行一直优化为无需计算的打印语句?
编辑: 大多数答案说编译器永远不能内联/消除堆分配的仿函数。但这也是真的吗?大多数编译器(GCC、MS、Intel)也有链接时间优化,它们确实可以进行这种优化。 (但有吗?)
【问题讨论】:
-
或许将其声明为静态函数会更好。
-
operator() 不能成为静态函数。
-
正确答案是#2 或#3。 (#3可能会更快,具体取决于优化器,但#2看起来更好/更干净)。 可能仍然在堆栈上分配空间,但与堆分配相比,4 个字节不算什么...
标签: c++ optimization compiler-construction functor