boost :: transform vs std :: transform

时间:2016-01-17 11:36:47

标签: algorithm boost transform std

从下面的代码段中我可以得出结论:std::transform优先于boost::transform,因为它可能更有效率,因为前者比后者使用更少的初始化和析构函数?

#include <algorithm>
#include <boost/range/algorithm.hpp>
class Ftor {
public:
  Ftor(const Ftor& rhs) : t(rhs.t) 
  {
    std::cout << " Ftor : copy" << std::endl;
  }
  Ftor(float rate) : t(rate) 
  {
    std::cout << " Ftor : init" << std::endl;
  }
  ~Ftor() { 
    std::cout << "~Ftor : ..." << std::endl;
  }
  float operator() (float x) { return (x<t?0.0:1.0);}
private:
  float t;
};

typedef std::vector<float> vec_t;

int main (void) 
{
  vec_t arg(/*...*/);
  vec_t val(arg.size());
  float x=1.0;
  /* STL transform test */
  std::cout << "STL transform: " << std::endl;
  std::transform(arg.begin(),arg.end(),val.begin(),Ftor(x));
  std::cout << "Boost transform: " << std::endl;
  /* Boost transform test */
  boost::transform(boost::make_iterator_range(arg.begin(),arg.end()),
                   val.begin(),Ftor(x));

}

输出:

STL transform: Ftor : init ~Ftor : ... Boost transform: Ftor : init Ftor : copy ~Ftor : ... ~Ftor : ...

STL转换使用2个调用。 Boost变换使用4个调用。 STL变换获胜。或者是......?

附录

正如@sehe建议std::ref每次调用transform时保存一个构造函数,boost::transform只使用一次调用。但std::ref不能暂时作为论据。但是,通过Ftor f(x)很好,因为后者有明确的地址。

在循环内调用transform时计算构造函数/析构函数的调用。我现在有两种选择:

std::cout << "with std::ref" << std::endl;
for(/*...*/) {
  x=...;
  f=Ftor(x);
  boost::transform(arg,val.begin(),std::ref(f));
}

std::cout << "with temporary" << std::endl;
for(/*...*/) {
  x=...;
  boost::transform(arg,val.begin(),Ftor(x));
}

输出:

with std::ref Ftor : init Ftor : init ... ~Ftor : ... with temporary Ftor : init Ftor : copy ~Ftor : ... ~Ftor : ... Ftor : init Ftor : copy ~Ftor : ... ~Ftor : ... ...

我有一个gcc(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4 有或没有-O3产生相同的结果。

构造函数/析构函数是否“昂贵”是相对于operator()。它是最终产品,它将执行不太苛刻的数学运算,与上面的例子不同。

Complete example

1 个答案:

答案 0 :(得分:4)

允许STL算法复制其谓词/仿函数。这主要是因为它们是按价值传递的。

您看到的是boost 一个更多的正向呼叫。

有问题吗?

通常不会。编译器非常擅长内联,复制省略和依赖性分析。

有可能,生成的代码最终完全相同。

  

当然,添加cout语句完全破坏了这一点。比较生成的代码没有构造函数/析构函数的副作用会破坏它!

公平比较using no-side-effects为STL和Boost变体生成相同的代码:http://paste.ubuntu.com/14544891/

修复

STL(和boost算法)的设计方式,如果需要,可以通过引用明确地传递仿函数。您可以使用std::ref

<强> Live On Coliru

#include <algorithm>
#include <vector>
#include <iostream>
#include <functional>
#include <boost/range/algorithm.hpp>

class Ftor {
  public:
    Ftor(const Ftor &rhs) : t(rhs.t) { std::cout << " Ftor : copy" << std::endl; } 
    Ftor(float rate) : t(rate)       { std::cout << " Ftor : init" << std::endl; } 
    ~Ftor()                          { std::cout << "~Ftor : ..."  << std::endl; } 
    float operator()(float x)        { return x; }  

  private:
    float t;
};

typedef std::vector<float> vec_t;

int main(void) {
    vec_t arg(190, 1), val(arg.size());

    {
        std::cout << "STL transform: " << std::endl;
        Ftor f(1.0);
        std::transform(arg.begin(), arg.end(), val.begin(), std::ref(f));
    }
    std::cout << "-----\n";

    {
        std::cout << "Boost transform: " << std::endl;
        Ftor f(1.0);
        boost::transform(arg, val.begin(), std::ref(f));
    }
    std::cout << "-----\n";
}

打印

STL transform: 
Ftor : init
~Ftor : ...
-----
Boost transform: 
Ftor : init
~Ftor : ...
-----

注意无论一切都是非常具有讽刺意味在容器上使用范围算法并构建范围boost::make_iterator_range(arg.begin(), arg.end())而不是仅使用arg }:

boost::transform(arg, val.begin(), Ftor(x));