我应该使用函数还是无状态函子?

时间:2011-04-02 07:41:31

标签: c++ function stl functor

这两段代码做同样的事情。如您所见,它将用于排序功能。 哪个更好?我通常写后一个。但是我看到有些程序员像前者那样做。

struct val_lessthan : binary_function<pair<string,int>, pair<string, int>, bool>
{
    bool operator() (const pair<string,int>& x, const pair<string,int>& y) const
    {
        return x.second < y.second;
    }
} val_lt;

bool val_lt(const pair<string,int>& x, const pair<string,int>& y) 
{
    return x.second < y.second;
}

将使用它:

std::sort(wordvector.begin(), wordvector.end(), val_lt);

6 个答案:

答案 0 :(得分:5)

第一个称为函数对象,如果需要将任何上下文信息传递给比较函数,则非常有用。独立函数仅获得xy,并且没有机会携带任何上下文。

在上面的具体实例中,编写比较函数的两种方法大致相同。

答案 1 :(得分:4)

您认为某些人更喜欢第一个版本的原因是仿函数可以简单地内联。

当你将一个仿函数传递给std::sort时,函数已知仿函数类型,因此调用的确切函数在编译时也是已知的,并且可以简单地内联。

使用普通函数,std::sort实际看到的只是一个函数指针,并且在编译时没有说明指向哪个函数。除非编译器执行一些相当广泛的流分析以查看指针来自此特定调用中的的位置,否则无法内联。并且它肯定会在像你这样的小例子中进行优化,但是如果函数/函数指针作为函数参数从其他地方传入,或者在传递给{{之前从中间数据结构中读取它1}},那么,编译器可能无法内联函数指针版本,因此最终会变慢。

答案 2 :(得分:1)

我可能更喜欢第一个,但通常更喜欢使用模板:

template <class T>
struct val_lessthan : binary_function<pair<pair<T, T>, bool> {
    bool operator()(T const &x, T const &y) const { 
       return x.second < y.second;
    }
};

.second的使用限制了通用度,但你仍然得到一点(例如,如果内存服务,boost::tuple为元组提供了.first.second两个元素。作为一个规则,作为一个模板可以更好地保证编译器能够内联生成代码,所以如果你关心效率,它可能会有所帮助(或者可能没有,但不太可能造成任何伤害。)

答案 3 :(得分:1)

如果您希望能够在代码的其他部分调用该函数,而不是作为仿函数传递,则更喜欢函数形式。例如,您更喜欢:

if (val_lt(a,b))
{
//...
}

if(val_lessthan()(a,b))
{
// ...
}

否则,在选择仿函数表单时,最好使用未命名的仿函数对象进行调用。那就是:

std::sort(wordvector.begin(), wordvector.end(), val_lesstthan());

而不是:

val_lesstthan named;
std::sort(wordvector.begin(), wordvector.end(), named);

Unnaming参数和返回值可以轻松地使编译器执行优化。它指的是一种称为RVO(返回值优化)的全局概念。在这种情况下,它可能会从一个副本构造中释放您的代码。

答案 4 :(得分:0)

我会说,选择最适合您特定情况的最简单的。在这种情况下,在第一个选择第二个。

答案 5 :(得分:-2)

两者都同样快。几乎可以忽略不计。

使用仿函数时,意味着函数operator()在编译器生成的代码中有三个参数,第一个参数是指向val_lt对象本身的指针,第二个和第三个参数是您在签名中提到的参数。像这样:

//the possible code generated by the compiler!
bool operator() (val_lessthan *_this, const pair<string,int>& x, const pair<string,int>& y) const
              //^^^^^^^^^^^^^^^^^^^ note this!
{
    return x.second < y.second;
}