4

当使用带有静态成员函数而不是仿函数样式谓词的模板参数时,是否有任何性能优势?

例如,仿函数风格的排序接口通常是这样的:

template <typename _Type, typename _Pred>
void sort (
    RandomAccessIterator first,
    RandomAccessIterator last ,
    _Pred less_than
    )
{
// actual sorting code here, calling less_than()...
}

你可以做更多这样的事情,并要求_Pred包含一个静态成员函数_Pred::less_than

template <typename _Type, typename _Pred>
void sort (
    RandomAccessIterator first,
    RandomAccessIterator last
    )
{
// actual sorting code here, calling _Pred::less_than()...
}

理论上,第一种情况可能会在堆上动态创建一个临时函子对象,而我相信第二种情况在编译时已被完全评估。我知道(比如说)gcc 和/或 msvc 擅长优化,但是在第一种情况下可以做到同样的程度吗?

另外,我不是要重写 STL 排序例程或类似的东西,只是一个更一般的仿函数问题的例子......

4

5 回答 5

4

正常使用sort不会将任何东西放在堆上,原因很简单,没有人调用mallocor new。如果您的谓词在其构造函数或比较中导致调用mallocor ,那么您只能责怪自己......new

某些堆栈将用于类型参数是合理的_Pred(您不能_Pred在代码中调用模板参数,因为_Pred它是保留符号。它可以在 的实现中调用std::sort)。但是除了谓词对象可能具有的任何数据成员所需的工作之外,不会有任何相关的工作要做。如果谓词没有数据成员,那么优化器将有一个字段 day,如果它确实有数据成员,那么静态成员函数将不支持用户想要做的事情。

只要operator()谓词中的谓词是非虚拟的,编译器就可以将其内联到sort它是否可以看到定义以及感觉最好的实例中。当然不能保证什么会更快,但是没有理由假设对静态成员函数的调用比对非虚拟非静态成员函数的调用更快或更慢,也没有理由认为它更容易或更难排队。

于 2010-12-09T01:01:57.380 回答
1

理论上,第一种情况可能会在堆上动态创建一个临时函子对象,而我相信第二种情况在编译时已被完全评估。

第一种情况将在堆栈上创建一个临时仿函数对象。您是否担心是否Pred::Pred()会分配存储空间?如果是这样,您可能还担心静态函数是否会出于某种原因在堆上分配存储空间。

无论如何,大多数使用这种习惯用法的谓词函子对象都有非常简单的构造函数,因为它们的唯一目的是调用重载的operator (),因此编译器可能会优化对象构造并产生简单的函数调用。

于 2010-12-09T00:56:41.980 回答
0

在第一种情况下,您可以创建一个

template<class T>
struct CompareByIntProperties {
    CompareByIntProperties(vector<T::*int> props) : props_(props) {}
    bool less_than(const T& a, const T& b) const {
        for (vector<T::*int>::const_iterator it = props_.begin();
             it != props_.end(); ++it) {
            if (a.(**it) < b.(**it)) return true;
            if (a.(**it) > b.(**it)) return false;
        }
        return false;
    }
    vector<T::*int> props_;
};

这将允许您

vector<Foo::*int> properties;
if (compare_foo) properties.push_back(&Foo::foo);
if (compare_bar) properties.push_back(&Foo::bar);
if (compare_qux) properties.push_back(&Foo::qux);
sort(container.begin(), container.end(), CompareByIntProperties<Foo>(properties));

请原谅任何语法错误,这些都没有经过编译检查。但你明白了。

在第二种情况下,因为您正在调用静态方法,所以您没有自由支配这样的自定义比较器。

我不会担心效率。如果你没有访问任何非静态的东西,一个好的 C++ 编译器会省略额外的对象创建/销毁,甚至可能内联比较器。

于 2010-12-09T00:58:57.447 回答
-1

如果_Pred::less_than不是虚拟的,则两种解决方案都是相同的,因为编译器确切地知道它是什么函数,并且可以在需要时内联。

那是假设我正确理解了您的代码-真实的代码会更清楚。我假设代码 1 执行类似的操作if (less_than.compare(a, b)),而代码 2 执行if (_Pred::less_than(a, b))

编辑:我应该提到示例 1 将按值传递对象,因此您将承担可能涉及的任何成本(如复制构造函数)。

于 2010-12-09T00:50:48.407 回答
-1

如果我是你,我将不再担心你是否会通过一种方式而不是另一种方式来购买微纳秒......并且更担心不使用保留的名称!

在担心这样的废话之前,您还有很长的路要走。当你到达那里时......希望你已经知道担心这样的废话是没有意义的。

不过,为了使它成为“答案”:两者都不是,您的程序格式不正确。

于 2010-12-09T00:55:06.620 回答