2013-07-09 67 views
1

所以std :: array和boost :: array(幾乎是相同的,我將在下文中將其簡稱爲「數組」)被設計爲爲數組提供一個容器對象,而不會產生向量的開銷如果數組不動態更改大小,則不必要。但是,它們都是通過將數組大小不作爲構造函數參數而設計爲模板參數來設計的。結果是:向量允許在創建對象後進行動態調整大小;數組需要在編譯時知道大小。我可以看到,如果你有一個數組,你會知道它在創建對象時的大小,而不是在編譯時,那麼你唯一的選擇是1)通過使用向量不必要地招致額外的開銷,2)使用(非容器類型)本地數組(例如,int foo[42];),或3)從頭編寫自己的數組包裝類。所以這是正確的,這是一個介於兩者之間的情況,你可能想使用數組而不是矢量,但不能?還是有一些我可以做的魔術,可能會爲我工作?在這種情況下可以使用std :: array(或boost :: array),還是我堅持使用std :: vector和native數組?

這裏有一個小細節(好吧,很多)上有什麼啓發了這個問題,在情況下,它可以幫助你理解:

我有一個模塊 - 比如來電 - 將反覆在運行時產生的二進制數據(無符號char []或數組),然後將它傳遞給另一個模塊 - 比如被調用者。被調用模塊不會修改數組(它會進行復制並在必要時進行修改),因此一旦調用者模塊最初創建數組,它將不會更改大小(實際上不是內容)。但是,會出現兩個問題:1)每次生成數組時,調用者都可能不會生成相同大小的數組 - 它會在創建數組時在rutime時知道數組大小,但不會在編譯時生成數組大小。 2)調用者將數組傳遞給被調用者的方法需要能夠獲取調用者傳遞給它的任何大小的數組。

我考慮使其成爲一個模板函數,例如,

template<size_t N> void foo(const array<unsigned char, N>& my_array); 

然而,我使用的接口類從被叫方模塊中實現分離的接口。因此,該功能必須是虛擬方法,與模板相互排斥。此外,即使這不是問題,它仍然會有與上面#1相同的問題 - 如果在編譯時未知數組大小,那麼它在編譯時也無法解析模板化函數。

我的實際功能可按:

virtual void foo(const array<unsigned char, N>& my_array); // but what is N??? 

因此,在總結,我是正確的,我唯一真正的選擇是使用矢量或本機陣列,例如,

virtual void foo(const vector<unsigned char> my_array); // unnecessary overhead 
virtual void foo(const unsigned char[] my_array, size_t my_array_len); // yuk 

或者是有一些訣竅我忽略這將讓我使用std :: array或boost :: array?

+2

C++ 14有'std :: dynarray'和運行時大小的數組。 – chris

+0

您是否確定了'std :: vector'需要多少開銷,並將其標識爲問題?我問,因爲它實際上是非常小的開銷(如果你正確使用它,每個容器有一個額外的指針):'std :: dynarray'的很大優勢實際上是基於堆棧的存儲的可能性。 – Yakk

+0

是的,事實是std :: vector的開銷可能不會殺死我......這就是我現在正在墮落的東西。 –

回答

1

你根本無法使用任何形式的std ::的數組,如果你不知道在編譯時間長度。

如果您在編譯時不知道數組的大小,請認真考慮使用std :: vector。使用可變長度數組(如int foo[n])不是標準的C++,如果給定的長度足夠大,會導致堆棧溢出。你也不能用(比std :: vector)更少的開銷來編寫任何類似數組的包裝器。

我只想用

virtual void foo(const unsigned char* my_array, size_t my_array_len); 

,並調用它像

obj.foo(&vec[0], vec.size()); 

沒有附加開銷,並且它你想要做什麼。除了普通數組(int foo[42])之外,還可以使用向量和std ::數組調用零開銷。

+0

/你可以寫一個比std :: vector少一點的開銷,只需一個很小但可測量的數量。需要花費一些努力才能使它像'std :: vector'一樣穩定,並且每個容器都會保存一個指針。除非你有100萬個含有少量數據(0到3個指針大小或更小的元素)的'矢量',或者正在emebedded系統上開發,否則黑盒子會注意到這種差異。 – Yakk

+0

感謝您的回答,@RareBox。我試圖避免這種情況,因爲my_array和my_array_len不是同一個對象的一部分,因此調用者需要跟蹤兩件事情。 std :: vector和std :: array跟蹤你的大小,所以作爲被調用者,我可以使用size()方法,並確定我得到正確的答案。所以我現在決定只使用向量並且承擔開銷,並且只有當我看到性能問題(在這種情況下可疑時,說實話),然後我將使用char *和size參數方法。 –

3

直到我們在C++ 11有std::dynarray,您可以使用std::unique_ptr

std::unique_ptr<Foo[]> arr(new Foo[100]); 

您可以使用此作爲arr[0]arr[1]等,並在破壞它會調用正確的delete[]。開銷很小(只是指針)。

我認爲一個數組類型的唯一的指針和std::dynarray之間的唯一區別是,後者具有迭代器和與其他size「containery」的屬性,並且它會是「集裝箱」部分中,而不是「一般公用事業」。 [更新:這編譯器可以選擇本地支持dynarray和優化使用堆疊式儲存]

+0

std :: dynarray背後的動機是它可以有選擇地從堆棧中分配它的內存。這是C99s可變長度數組的替代品。 dynarray很可能C++ 14 – RareBox

+0

@RareBox:另外,C++ 14將*也*具有可變長度數組。 (但你說得對,N2648建議'std :: dynarray'的堆棧分配爲QoI。) –

0

其他注意事項:

  • 數組是在棧上分配。這比快於在堆上分配。
  • 數組創建時總是初始化所有元素。

所以:

class Foo; 
    std::array<Foo, 100> aFoo; 

構造100個Foo對象(調用Foo::Foo() 100次),而100個Foo對象(在堆上)

std::vector<Foo> vFoo; 
    vFoo.reserve(100); 

預留空間,但不構建其中的任何一個。