簡體   English   中英

std :: list是否有一個等效的vector :: reserve()?

[英]Is there an equivalent of vector::reserve() for an std::list?

我有一個看起來像這樣的課程:

typedef std::list<char*> PtrList;
class Foo
{
public:
   void DoStuff();
private:
   PtrList m_list;
   PtrList::iterator m_it;
};

函數DoStuff()基本上將元素添加到m_listm_list刪除元素,找到一個特殊元素的迭代器並將其存儲在m_it 值得注意的是, m_it每個值都在DoStuff()每個后續調用中使用。

所以有什么問題? 一切正常,除了分析顯示由於從DoStuff()調用的list::push_back()而調用operator new太多。

為了提高性能,我想在Foo的初始化中為m_list預分配內存, m_list它是一個std::vector 問題是這會引入新的問題,例如:

  1. 元素的inserterase效率較低。
  2. 一旦向量從一個調用更改為DoStuff()到下一個調用, m_it就會變為無效。 編輯:艾倫斯托克斯建議使用索引而不是迭代器,解決這個問題。

我的解決方案:我能想到的最簡單的解決方案是實現一個也具有鏈表功能的對象池。 這樣我就可以得到一個鏈表, 可以為它預先分配內存。

我錯過了什么或者它是否真的是最簡單的解決方案? 我寧願不“重新發明輪子”,而是使用標准解決方案,如果存在的話。

任何想法,變通方法或啟發性評論將不勝感激!

我認為你錯了容器。

如果你想快速推回然后不自動假設你需要一個鏈表,一個鏈表是一個緩慢的容器,它基本上適合重新排序。

一個更好的容器是std :: deque。 deque基本上是一個數組數組。 它會分配一塊內存並在你向后推時占用它,當它用完時會分配另一個塊。 這意味着它只是很少分配,你不必提前知道容器的大小,比如std :: vector和reserver

您可以使用std::listsplice函數來實現池。 添加一個新的成員變量PtrList m_Pool 如果要添加新對象且池不為空,請將值分配給池中的第一個元素,然后將其拼接到列表中。 要擦除元素,請將其從列表中拼接到池中。

但是如果你不關心元素的順序,那么deque可以更快。 如果要刪除中間的元素,請將最后一個元素復制到要刪除的元素上,然后刪除最后一個元素。

我的建議與111111相同,在編寫任何重要代碼之前嘗試切換到deque

但是,要直接回答您的問題:您可以將std::list與自定義分配器一起使用。 它有點繁瑣,我不會在這里完成所有細節,但它的要點是你編寫了一個代表列表節點的內存分配策略的類。 list分配的節點將是一個小於實現定義的大於char* ,但它們都將具有相同的大小,這意味着您可以只為該大小編寫一個優化的分配器(一個內存塊池而不是一個池對象),你可以添加函數,讓你在你想要的時候在分配器中保留你想要的任何空間。 然后列表可以快速分配/釋放。 這節省了您需要重新實現任何實際list功能。

如果您(由於某種原因)要實現具有列表功能的對象池,那么您可以從boost::intrusive開始。 在編寫自己的分配器時,這可能也很有用,可以跟蹤您的空閑塊列表。

可能使用list::get_allocator().allocate() Afaik,默認行為是由於list s的非連續性而隨時獲取內存 - 因此缺少reserve() - 但是使用allocator方法沒有立即出現的主要缺點。 如果您的計划中有非關鍵部分,在開始時或其他任何部分,您至少可以選擇在此時獲取損害。

列表和向量在管理對象的方式上完全不同。

Vector將元素構造到給定容量的已分配緩沖區中。 當容量耗盡時,會發生新的分配。 列表逐個分配元素,每個元素分配到一個單獨分配的空間。

插入/移除某些內容時,向量元素會移位,因此,向量索引和元素地址不穩定。 插入/刪除某些內容時,List元素會重新鏈接,因此,列表迭代器和元素地址是穩定的。

使列表行為與向量類似的方法是替換默認分配器(每次調用時分配系統)與另一個分配較大塊中的對象,在調用子塊時將子塊分派給列表它。 這不是標准庫默認提供的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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