最佳化 C++/編寫高效程式碼/分配和釋放
與自動記憶體分配和釋放相比,動態記憶體分配和釋放是非常慢的操作。換句話說,堆比棧慢得多。
此外,動態分配會產生每次分配的開銷,會導致虛擬記憶體碎片化,並導致不良的資料區域性性引用,進而導致處理器資料快取和虛擬記憶體空間的糟糕使用。
在 C 語言中,動態記憶體分配/釋放使用 `malloc` 和 `free` 標準庫函式完成。在 C++ 中,雖然這些函式仍然可用,但通常使用 `new`、`new[]`、`delete` 和 `delete[]` 運算子。
減少分配次數的一個明顯方法是減少構造物件的數量,為此,您應該參考本章的“構造和析構”部分。
這裡我們集中於減少給定數量的 `new` 運算子呼叫時的分配次數的指南。
如果靜態或非大型陣列具有編譯時常量長度,則應使用 C 語言陣列、std::array 或來自 Boost 庫的 `array` 物件,而不是 `vector` 物件。
`vector` 在動態分配的緩衝區中儲存資料,而陣列在物件本身內部分配資料。這避免了重複的動態記憶體分配/釋放,並有利於資料區域性性。
如果陣列很大,這些優勢就會減少,避免使用過多的堆疊空間變得更加重要。
如果您必須分配許多相同大小的物件,請使用塊分配器。
一個 塊分配器(又稱池分配器)分配中等至大型記憶體塊,並提供分配/釋放較小固定大小塊的服務。它允許高速分配/釋放、低記憶體碎片化以及對資料快取和虛擬記憶體的有效利用。
特別是,這種分配器可以大大提高 `std::list`、`std::set`、`std::multiset`、`std::map` 和 `std::multimap` 標準容器的效能。
如果您的標準庫實現尚未為這些容器使用塊分配器,您應該獲取一個並將其指定為這些容器模板例項的模板引數。Boost 提供了兩個可自定義的塊分配器,`pool_allocator` 和 `fast_pool_allocator`。其他池分配器庫可以在全球資訊網上找到。始終先進行測量,以找到最適合手頭工作的分配器。
當您必須將元素追加到集合時,使用 `push_back` 追加單個元素,使用 `insert` 追加一系列元素,並使用 `back_inserter` 使 STL 演算法將元素追加到序列。
`push_back` 函式保證攤銷線性時間,因為在 `vector` 的情況下,它會以指數方式增加容量。
`back_inserter` 類在內部呼叫 `push_back` 函式。
`insert` 函式允許以最佳化方式插入整個序列,因此單個 `insert` 呼叫比多次呼叫 `push_back` 更快。