我知道這std::function
是用型別擦除習語實作的。型別擦除是一種方便的技術,但作為一個缺點,它需要在堆上存盤底層物件的暫存器(某種陣列)。
因此,在創建或復制function
物件時,需要進行分配,因此該程序應該比簡單地將函式作為模板型別進行操作要慢。
為了檢查這個假設,我運行了一個累積n = cycles
連續整數的測驗函式,然后將總和除以增量數n
。首先編碼為模板:
#include <iostream>
#include <functional>
#include <chrono>
using std::cout;
using std::function;
using std::chrono::system_clock;
using std::chrono::duration_cast;
using std::chrono::milliseconds;
double computeMean(const double start, const int cycles) {
double tmp(start);
for (int i = 0; i < cycles; i) {
tmp = i;
}
return tmp / cycles;
}
template<class T>
double operate(const double a, const int b, T myFunc) {
return myFunc(a, b);
}
和main.cpp
:
int main()
{
double init(1), result;
int increments(1E9);
// start clock
system_clock::time_point t1 = system_clock::now();
result = operate(init, increments, computeMean);
// stop clock
system_clock::time_point t2 = system_clock::now();
cout << "Input: " << init << ", " << increments << ", Output: " << result << '\n';
cout << "Time elapsed: " << duration_cast<milliseconds>(t2 - t1).count() << " ms\n";
return 0;
}
這運行了一百次,得到的平均結果為10024.9 ms
.
然后我在 中引入function
物件main
,加上一個模板特化,operate
這樣上面的代碼就可以被回收:
\\ as above, just add the template specialization
template<>
double operate(const double a, const int b, function<double (const double, const int)> myFunc) {
cout << "nontemplate called\n";
return myFunc(a, b);
}
\\ and inside the main
int main()
{
//...
// start clock
system_clock::time_point t1 = system_clock::now();
// new lines
function<double (const double, const int)> computeMean =
[](const double init, const int increments) {
double tmp(init);
for (int i = 0; i < increments; i) {
tmp = i;
}
return tmp / increments;
};
// rest as before
// ...
}
我預計function
版本會更快,但平均值差不多,實際上甚至更慢,result = 9820.3 ms
. 檢查標準偏差,它們大致相同,1233.77
與1234.96
.
這有什么意義?我本來希望帶有function
物件的第二個版本比模板版本慢。
這里整個測驗可以在 GDB 上運行。
uj5u.com熱心網友回復:
我知道這
std::function
是用型別擦除習語實作的。型別擦除是一種方便的技術,但作為一個缺點,它需要在堆上存盤底層物件的暫存器(某種陣列)。
型別擦除不一定需要堆分配。在這種情況下, 的實作很可能std::function
不必進行任何堆分配,因為 lambda 不捕獲任何變數。因此,std::function
只需將函式指標存盤在物件本身中,而不是在堆分配的記憶體中。
除此之外,即使std::function
做了堆分配,一些編譯器甚至可能會忽略那些堆分配。
最后但同樣重要的是,雖然堆分配比堆疊分配更昂貴,但如果您只需要在整個程式期間在堆上分配一次,您可能不會注意到由于該分配而導致的任何時間差異。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/478098.html