boost::transform 对比 std::transform
boost::transform vs std::transform
根据下面的代码片段,我是否应该得出结论,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));
}
输出:
Standard transform:
Ftor : init
~Ftor : ...
Boost transform:
Ftor : init
Ftor : copy
~Ftor : ...
~Ftor : ...
标准转换使用 2 次调用。 Boost 变换使用 4 次调用。标准变换获胜。还是……?
附录
正如@sehe 所建议的那样,std::ref
每次调用 transform
时保存一个构造函数,而 boost::transform
仅使用一次调用。但是 std::ref
不能将临时参数作为参数。但是,传递 Ftor f(x)
就可以了,因为后者有一个明确的地址。
考虑在循环内调用 transform 时的 constructor/destructor 调用。我现在有两种选择:
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));
}
输出:
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
都会产生相同的结果。
constructor/destructor是否“贵”是相对于operator()
来说的。它是最终产品,它将执行不太苛刻的数学运算,与上面的示例没有什么不同。
允许STL算法复制它们的predicate/functors。这主要是因为它们是按值传递的。
你看到的是 boost
做了 一次 前向调用。
有问题吗?
通常不会。编译器非常擅长内联、复制省略和依赖分析。
很有可能,生成的代码最终完全相同。
Of course, adding the cout
statements completely wrecks that. Compare generated code without the constructor/destructor side-effects spoiling it!
公平比较using no-side-effects generates identical code for the STL and Boost variants: http://paste.ubuntu.com/14544891/
修复
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";
}
版画
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));
根据下面的代码片段,我是否应该得出结论,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));
}
输出:
Standard transform:
Ftor : init
~Ftor : ...
Boost transform:
Ftor : init
Ftor : copy
~Ftor : ...
~Ftor : ...
标准转换使用 2 次调用。 Boost 变换使用 4 次调用。标准变换获胜。还是……?
附录
正如@sehe 所建议的那样,std::ref
每次调用 transform
时保存一个构造函数,而 boost::transform
仅使用一次调用。但是 std::ref
不能将临时参数作为参数。但是,传递 Ftor f(x)
就可以了,因为后者有一个明确的地址。
考虑在循环内调用 transform 时的 constructor/destructor 调用。我现在有两种选择:
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));
}
输出:
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
都会产生相同的结果。
constructor/destructor是否“贵”是相对于operator()
来说的。它是最终产品,它将执行不太苛刻的数学运算,与上面的示例没有什么不同。
允许STL算法复制它们的predicate/functors。这主要是因为它们是按值传递的。
你看到的是 boost
做了 一次 前向调用。
有问题吗?
通常不会。编译器非常擅长内联、复制省略和依赖分析。
很有可能,生成的代码最终完全相同。
Of course, adding the
cout
statements completely wrecks that. Compare generated code without the constructor/destructor side-effects spoiling it!
公平比较using no-side-effects generates identical code for the STL and Boost variants: http://paste.ubuntu.com/14544891/
修复
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";
}
版画
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));