为什么boost :: function慢?

时间:2012-12-06 16:20:27

标签: c++ performance boost

我正在做一些计时测试,我的一个测试是比较调用函数的不同方法。我用各种方法调用了N个函数。我尝试了常规函数调用,虚函数调用,函数指针和boost :: function。

我在Linux中使用gcc和-O3优化做到了这一点。

正如预期的那样,虚拟调用比常规函数调用慢。然而令人惊讶的是,boost :: function的速度比虚拟调用慢了33%。

有没有人注意到这个?对此为何的任何线索?

3 个答案:

答案 0 :(得分:6)

如果可能,编译器可以内联常规函数,但boost::function可以从不内联。这是一个很大的不同。

第二个区别是,boost::function实现了type-erasure,这意味着它使用间接来调用实际的函数。意味着它首先调用一个虚函数,然后调用你的函数。所以通常它涉及(最少)两个函数调用(其中一个是virtual)。这是巨大的差异。

因此,基于此分析,可以推断出这一点(甚至没有编写测试代码):

slowest ------------------------------------------------------> fastest 
        boost::function < virtual function < regular function 
slowest ------------------------------------------------------> fastest

在您的测试代码中确实如此。

请注意,对于std::function也是如此(自C ++ 11起可用)。

答案 1 :(得分:2)

boost::function不仅可以包含一个函数指针,还可以包含一个任意对象的整个副本,它可能会调用虚拟operator()

它可以帮助理解它是如何工作的(对于说明)。

以下是boost::function类型技巧的玩具实现:

struct helper_base { virtual void do_it() = 0; };
template<typename Func>
struct helper:helper_base {
  Func func;
  helper(Func f):func(f) {}
  virtual void do_it() override { func(); }
};
struct do_something_later {
  boost::unique_ptr<helper_base> pImpl;
  template<typename Func>
  do_something_later( Func f ):pImpl(make_shared<helper<Func>>(f))
  {}
  void operator()() { (*pImpl).do_it(); }
private:
  do_something_later( do_something_later const& ); // deleted
  void operator=( do_something_later const& ); // deleted
};

这里我的do_something_later接受任意对象(Func)并根据需要调用operator()。它在类型擦除帮助器中包装我们调用operator()的东西的类型,然后通过虚函数调用operator()

Func类型可以是函数指针,也可以是带状态的函子。任何可以与运营商()复制的东西都是公平的游戏。就do_something_later的用户而言,只有一个二进制接口。

boost::function(和std::function)基本上使用相同的技术(有很多改进)将一整套可能的接口转换为一个接口。成本涉及调用virtual函数(或等效的间接函数)。

答案 2 :(得分:0)

观察到的缓慢的真正原因是除了两个间接之外,boost::function将指针与零进行比较。如果省略了这个测试,那么调用将像虚函数一样快(这也涉及两个间接 - 一个指向vtable的指针,另一个指向实际函数)。