Video thumbnail for Stop using std::vector wrong

C++ std::vector 正確用法:避免錯誤,提升效能!

Summary

Language:

Quick Abstract

C++ STD Vector 是強大卻易被誤用的工具。本摘要將剖析 STD Vector 的常見誤用方式,並提供提升效能的實用技巧。了解何時及如何正確使用,避免不必要的資源浪費,提升程式效率。本篇將著重於效能優化,探討記憶體分配、複製與移動的影響,助您寫出更精簡、高效的 C++ 程式碼。

Quick Takeaways:

  • 優先考慮 std::array 在已知大小的情況下,因為它在堆疊上分配,速度更快。

  • 使用 reserveresize 預先分配記憶體,減少動態調整大小的開銷。

  • 避免不必要的向量複製,使用 const reference 作為函數參數。

  • 使用 emplace_back 直接在容器中建構物件,避免複製和移動,直接將構造函數的參數傳遞給容器,在適當的位置直接構造對象。

  • 了解複製構造函數和移動構造函數的差異及其對效能的影響。

STD Vector 在 C++ 中是非常有用的工具,但同時也容易被誤用。本文將探討 STD Vector 的常見錯誤使用方式,並提供改進建議,以提升程式碼效能。

什麼是 STD Vector?

STD Vector 是 C++ 標準模板庫(STL)中的一種容器類型。它是一個動態調整大小的陣列,元素在記憶體中連續儲存。這使其兼具陣列的效率和動態調整大小的靈活性。

為何稱之為 Vector?

關於 Vector 這個名稱的由來,可能是設計者 Alex 隨意決定的,後來可能也後悔了。這也是 C++ 常見的情況。

效能考量

使用 STD Vector 的標準

本文主要關注如何提升 STD Vector 的效能。雖然 STL 並非專為極致效能而設計,但透過適當的使用方式,仍然可以大幅提升其效能。

STL 並非永遠最佳選擇

如果效能是首要考量,可能需要考慮其他替代方案,例如自行設計資料結構,或使用專為效能優化的函式庫,例如 EA 的 EASTL。EASTL 是為遊戲開發優化的 STL 版本,更注重速度和效能。

何時不該使用 STD Vector?

評估是否需要動態大小

使用 STD Vector 的首要原則是評估是否真的需要它。若能使用固定大小的陣列,則應優先考慮 std::array

Stack vs. Heap

std::array 儲存在堆疊 (Stack) 中,而 STD Vector 儲存在堆積 (Heap) 中。堆疊通常比堆積更快,因此在不需要動態調整大小的情況下,std::array 是更好的選擇。

範例:Tetris 程式碼審查

在 Tetris 程式碼審查中,get_cell_colors 函數返回一個顏色向量。由於顏色數量固定(8 種),因此使用 std::array<Color, 8> 會更有效率。

如何正確使用 STD Vector

避免不必要的複製

除非必要,否則避免複製 Vector。將 Vector 作為函數參數傳遞時,應使用 const 引用 (const &),以避免不必要的記憶體分配和元素複製。

預先分配記憶體

瞭解 Vector 的記憶體管理

Vector 在容量不足時會自動重新分配記憶體。在 MSVC 編譯器中,Vector 會以 50% 的幅度增長容量(例如,從 2 增加到 3)。Clang 也有類似的行為,而 GCC 則會將容量翻倍。這種自動增長可能導致頻繁的記憶體重新分配,降低效能。

使用 reserve() 預留空間

若預先知道 Vector 大約需要儲存多少元素,可以使用 reserve() 函數預留足夠的記憶體空間,避免不必要的重新分配。

使用 resize() 設定大小

resize() 函數可以設定 Vector 的大小,並使用預設建構子初始化新增的元素。如果之後需要覆寫這些元素,則效率不如 reserve()

避免複製,善用 emplace_back()

避免不必要的物件複製

盡可能避免在 Vector 中儲存物件時進行複製。複製物件可能會導致額外的記憶體分配和效能損失。

使用 emplace_back() 取代 push_back()

使用 emplace_back() 函數可以直接在 Vector 的記憶體空間中建構物件,避免先建構物件再複製到 Vector 的過程。這可以顯著提升效能。

移動語意 (Move Semantics)

了解 Move Semantics 的優勢

在 C++ 中,Move Semantics 允許將資源(例如堆積記憶體)從一個物件轉移到另一個物件,而無需進行複製。這可以大幅提升效能,尤其是在處理包含大量資料的物件時。

使用 Move Constructor

若類別包含指標或需要管理資源,應實作 Move Constructor。Move Constructor 可以將資源從來源物件轉移到新物件,並將來源物件設定為有效但未定義的狀態。

emplace_back() 與 Move Semantics 的結合

即使使用了 Move Constructor,emplace_back() 仍然比 push_back() 更有效率,因為它避免了物件的建構和轉移過程。

總結

  1. 評估是否需要 STD Vector:若不需要動態大小,使用 std::array
  2. 預先分配記憶體:使用 reserve()resize() 避免頻繁的重新分配。
  3. 避免複製:使用 emplace_back() 直接在 Vector 中建構物件。

透過遵循這些原則,可以更有效地使用 STD Vector,提升程式碼效能。

Was this summary helpful?

Quick Actions

Watch on YouTube

Related Summaries

No related summaries found.

Summarize a New YouTube Video

Enter a YouTube video URL below to get a quick summary and key takeaways.