从下面的代码段中我可以得出结论: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()
。它是最终产品,它将执行不太苛刻的数学运算,与上面的例子不同。
答案 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));