gpt4 book ai didi

c++ - boost::transform 与 std::transform

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:36:22 29 4
gpt4 key购买 nike

从下面的代码片段我应该得出结论,std::transformboost::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 时计算构造函数/析构函数调用。我现在有两个 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));
}

输出:

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 on coliru

最佳答案

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

您看到的是 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为 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));

关于c++ - boost::transform 与 std::transform,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34837866/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com