[英]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 時考慮構造函數/析構函數調用。 我現在有兩個 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()
而言的。 它是最終產品,將執行不太苛刻的數學運算,與上面的示例沒有什么不同。
允許 STL 算法復制它們的謂詞/函子。 這主要是因為它們是按值傳遞的。
您看到的是boost
又進行了一次前向調用。
通常不會。 編譯器非常擅長內聯、復制省略和依賴分析。
很有可能,生成的代碼最終完全相同。
當然,添加
cout
語句會完全破壞它。 比較生成的代碼,沒有構造函數/析構函數的副作用破壞它!
使用無副作用的公平比較為 STL 和 Boost 變體生成相同的代碼: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));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.