C++ boost::transform与std::transform
从下面的代码片段中,我是否应该得出这样的结论:C++ boost::transform与std::transform,c++,algorithm,boost,transform,std,C++,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 << "
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\n"; }
Ftor(float rate) : t(rate)
{ std::cout << " Ftor : init\n"; }
~Ftor()
{ std::cout << "~Ftor : ...\n"; }
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;
/* Standard transform test */
std::cout << "Standard transform:\n";
std::transform(arg.begin(), arg.end(), val.begin(), Ftor(x));
std::cout << "Boost transform:\n";
/* Boost transform test */
boost::transform(boost::make_iterator_range(arg.begin(), arg.end()),
val.begin(), Ftor(x));
}
标准转换使用2个调用。Boost transform使用4个调用。标准转换获胜。还是
附录
正如@sehe所建议的那样,std::ref
为transform
的每个调用保存一个构造函数,boost::transform
只使用一个调用。但是std::ref
不能将临时变量作为参数。但是,将传递到f(x)
是可以的,因为后者有一个明确的地址
在循环内调用transform时考虑构造函数/析构函数调用。我现在有两个boost选项:
std::cout << "with std::ref\n";
for (/*...*/) {
x = ...;
f = Ftor(x);
boost::transform(arg, val.begin(), std::ref(f));
}
std::cout << "with temporary\n";
for (/*...*/) {
x = ...;
boost::transform(arg, val.begin(), Ftor(x));
}
我有一个gcc(ubuntu4.8.4-2ubuntu1~14.04)4.8.4
有或没有-O3
产生相同的结果
构造函数/析构函数是否“昂贵”与操作符()有关。它是一个最终产品,它将执行不太苛刻的数学运算,与上面的例子没有什么不同
STL算法允许复制其谓词/函子。这主要是因为它们是按值传递的
您看到的是,boost
执行一个转发呼叫
有什么问题吗?
通常不会。编译器非常擅长内联、拷贝省略和依赖性分析
很可能,生成的代码最终完全相同
当然,添加cout
语句完全破坏了这一点。比较生成的代码,不要让构造函数/析构函数的副作用破坏它
公平比较为STL和Boost变体生成相同的代码:
修理
按照STL(和boost算法)的设计方式,如果需要,可以通过引用显式传递函子。您可以使用std::ref
进行以下操作:
#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";
}
注意不管发生什么,在容器上使用范围算法并构造一个范围boost::make_iterator_range(arg.begin(),arg.end())
而不是仅仅使用arg
,这是非常讽刺的:
boost::transform(arg, val.begin(), Ftor(x));
公平比较为STL和Boost变体生成相同的代码:公平比较的投票结果为向上。。。讽刺的是:DIf我替换了boost::transform(arg,val.begin(),std::ref(f))末尾附近的行代码>通过boost::transform(arg,val.begin(),std::ref(Ftor(1.0))代码>我得到一个错误:使用已删除的函数'void std::ref(const _Tp&)[with _Tp=Ftor]'。给出了什么?你不能安全地将引用传递给临时用户。这是一个内置于boosts引用包装类中的安全预防措施,因此,如果我在一个循环中有大量的transform
s,那么开销可能会计算在内。。。我更喜欢A:用于(/*…*/){tmp=Ftor(x);boost::transform(arg,val.begin(),std::ref(tmp));}
还是B:用于(/*…*/){boost::transform(arg,val.begin(),Ftor(x));}
编辑几乎没有意义。为什么成员变量t
甚至没有在functor中使用?return(xOh god.我真的需要检查我的眼睛。不管怎样,等待基准代码(或者代码试图实现什么。可能有更好的算法方法)重新编辑。这只是计算你不应该计算的东西。实际的基准在哪里?
boost::transform(arg, val.begin(), Ftor(x));