簡體   English   中英

從功能返回容器:優化速度和現代風格

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM