[英]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_list
或m_list
刪除元素,找到一個特殊元素的迭代器並將其存儲在m_it
。 值得注意的是, m_it
每個值都在DoStuff()
每個后續調用中使用。
所以有什么問題? 一切正常,除了分析顯示由於從DoStuff()
調用的list::push_back()
而調用operator new
太多。
為了提高性能,我想在Foo
的初始化中為m_list
預分配內存, m_list
它是一個std::vector
。 問題是這會引入新的問題,例如:
insert
和erase
效率較低。 DoStuff()
到下一個調用, m_it
就會變為無效。 編輯:艾倫斯托克斯建議使用索引而不是迭代器,解決這個問題。 我的解決方案:我能想到的最簡單的解決方案是實現一個也具有鏈表功能的對象池。 這樣我就可以得到一個鏈表, 並可以為它預先分配內存。
我錯過了什么或者它是否真的是最簡單的解決方案? 我寧願不“重新發明輪子”,而是使用標准解決方案,如果存在的話。
任何想法,變通方法或啟發性評論將不勝感激!
我認為你錯了容器。
如果你想快速推回然后不自動假設你需要一個鏈表,一個鏈表是一個緩慢的容器,它基本上適合重新排序。
一個更好的容器是std :: deque。 deque基本上是一個數組數組。 它會分配一塊內存並在你向后推時占用它,當它用完時會分配另一個塊。 這意味着它只是很少分配,你不必提前知道容器的大小,比如std :: vector和reserver
。
您可以使用std::list
的splice
函數來實現池。 添加一個新的成員變量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.