[英]Returning container from function: optimizing speed and modern style
雖然我一直在思考如何通過樣式更優雅地編寫這樣的代碼,同時又充分利用新的c ++標准等,但這並不是一個完整的問題。這是示例
將斐波那契數列返回到一個容器,該容器最多包含N個值(對於那些在數學上沒有傾斜的值,這只是將前兩個值與前兩個值等於1相加,即1,1,2,3,5,8,13,.. 。)
從main運行的示例:
std::vector<double> vec;
running_fibonacci_seq(vec,30000000);
1)
template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T& coll, const INT_TYPE& N)
{
coll.resize(N);
coll[0] = 1;
if (N>1) {
coll[1] = 1;
for (auto pos = coll.begin()+2;
pos != coll.end();
++pos)
{
*pos = *(pos-1) + *(pos-2);
}
}
}
2)相同,但使用右值 &&代替&1.e。
void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
編輯:正如下面評論的用戶所注意到的,右值和左值在計時中不起作用-由於評論中討論的原因,速度實際上是相同的
N的結果= 30,000,000
Time taken for &:919.053ms
Time taken for &&: 800.046ms
首先,我知道這確實不是一個問題,但是其中哪個是最好的現代c ++代碼? 使用右值引用(&&),似乎移動語義已經就位,並且沒有進行不必要的復制,這對時間有所改善(對我來說很重要,因為將來會進行實時應用程序開發)。 一些具體的“問題”是
a)將容器(在我的示例中為矢量)傳遞給函數作為參數,這並不是關於如何真正使用rvalue的完美解決方案。 這個事實是真的嗎? 如果是這樣,那么在上面的示例中rvalue到底如何顯示出來呢?
b) coll.resize(N); 調用和N = 1的情況下,有一種避免這些調用的方法,因此為用戶提供了一個簡單的界面,使其僅使用該函數而不動態創建向量的大小。 可以在這里使用模板元編程,以便在編譯時為向量分配特定的大小嗎? (即running_fibonacci_seq <30000000>),因為數字可能很大,是否有必要使用模板元編程,如果可以的話,我們是否也可以使用此(鏈接)
c)有沒有更優雅的方法? 我有一種感覺std :: transform函數可以通過使用lambdas使用,例如
void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
{
coll.resize(N);
coll[0] = 1;
coll[1] = 1;
std::transform (coll.begin()+2,
coll.end(), // source
coll.begin(), // destination
[????](????) { // lambda as function object
return ????????;
});
}
[1] http://cpptruths.blogspot.co.uk/2011/07/want-speed-use-constexpr-meta.html
明顯的答案:
std::vector<double> running_fibonacci_seq(uint32_t N);
為什么呢
由於穩定性:
std::vector<double> const result = running_fibonacci_seq(....);
由於更簡單的不變式:
void running_fibonacci_seq(std::vector<double>& t, uint32_t N) {
// Oh, forgot to clear "t"!
t.push_back(1);
...
}
但是速度如何?
在許多情況下,有一個稱為返回值優化的優化,該優化使編譯器可以省略副本(並直接在調用者的變量中生成結果)。 即使復制/移動構造函數有副作用 ,C ++標准也特別允許它。
那么,為什么要傳遞“ out”參數呢?
t
的內存緩沖區) 由於“引用崩潰”,此代碼不使用右值引用或移動任何內容:
template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T&& coll, const INT_TYPE& N);
running_fibonacci_seq(vec,30000000);
當您意識到這一點時,您所有的問題(以及現有的評論)將變得毫無意義。
對此進行簡介:
#include <vector>
#include <cstddef>
#include <type_traits>
template <typename Container>
Container generate_fibbonacci_sequence(std::size_t N)
{
Container coll;
coll.resize(N);
coll[0] = 1;
if (N>1) {
coll[1] = 1;
for (auto pos = coll.begin()+2;
pos != coll.end();
++pos)
{
*pos = *(pos-1) + *(pos-2);
}
}
return coll;
}
struct fibbo_maker {
std::size_t N;
fibbo_maker(std::size_t n):N(n) {}
template<typename Container>
operator Container() const {
typedef typename std::remove_reference<Container>::type NRContainer;
typedef typename std::decay<NRContainer>::type VContainer;
return generate_fibbonacci_sequence<VContainer>(N);
}
};
fibbo_maker make_fibbonacci_sequence( std::size_t N ) {
return fibbo_maker(N);
}
int main() {
std::vector<double> tmp = make_fibbonacci_sequence(30000000);
}
fibbo_maker
東西只是我很聰明。 但這使我無需重復就可以推斷出您想要的fibbo序列的類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.