C vector 的 push back 擴容機制為什麼不考慮在尾元素後面的空間申請記憶體

時間 2021-05-29 23:35:58

1樓:流石Lee

按我的理解,考慮到實際執行,等你需要擴容的時候,尾部未必預留了足夠的空間給你,你不知道(當然程式也不知道)執行時,容器的尾元素何時將被誰申請掉。

不是不可以考慮,或許這可以作為一種全域性的優化策略,譬如首先避免去申請容器尾元素後面的空間,但是這極難配合(還有其他程序在執行),另一種情況是重新申請你可以得到足夠大小,而擴容卻不能,這時候你選擇重新申請,還是丟擲bad_alloc呢?其他回答者回答得已經很好了(他們均從目前已實現的機制出發,來講解)

系統和編譯器是可以優化、進化的,譬如過去++i和i++都喜歡說有區別,但實際上至少在msvc的08和10上,反彙編得到的內容,僅僅在迭代器和複雜型別上還存在區別,內建型別已經幾乎一致。至於題主期望的尾元素擴容,會不會實現,不清楚,目前確實沒有,與其判斷這個判斷那個,還是直接重新申請來得便捷。

(可能表述會有點不當甚至有點飄,因為喝醉了=。=)

2樓:DLM-fakeS

你這個問題描述裡的 [1] 到底在說啥?擺脫能好好組織下語言嗎。

[1] 為什麼不先判斷 vector 尾元素之後的記憶體空間是否滿足擴容後的需求,

若滿足就直接在後面分配,而一律重新分配記憶體空間,再對所有元素做一次拷貝構造?

vector 本來就是自動擴充記憶體的容器。裡面有好幾個指標,有指向記憶體起始位置的,有指向記憶體的尾部位置的,capcity 就是通過這兩個指標做差後計算出來的。

當容器當前的 capcity 不夠用的時候,容器自動重新分配記憶體,擴充為之前的 capcity 的二倍。當然這裡面還有把之前的元素,複製到新分配的記憶體中的拷貝動作。如果 capcity 是夠用的,那麼 push_back 就把引數拷貝到容器內部維護的記憶體中的「尾部位置「(這時只有拷貝動作,沒有記憶體重新分配動作,capcity 不變,size 增加 1 )。

因此如果你能很好的提前預估容器裡面的元素數量,可以使用 reserve 提前分配好記憶體,再持續的放入元素。這樣就可以減少那些「自動擴充記憶體」的操作的次數。

如果嫌 capcity 中的冗餘太多,可以使用 shrink_to_fit 來把它維護的記憶體壓縮到合適大小。

3樓:濤哥

vector的擴容並非,在push_back時直接增加需要插入的記憶體大小。而是當記憶體不夠時直接對vector進行倍數擴容

C++標準規定vector有乙個擴容因子,在需要增加vector大小的時候,將vector容量擴充為為自身的(1,2]倍。(絕大多數情況是兩倍,但是並沒有硬性規定一定是兩倍,按照stl實現者自身的規定即可,也有擴容1.5倍的)

原因:

從兩個方面來分析

1.如若是不按倍數增長,只在每次push_back時加入記憶體會導致,push_back的平均時間複雜度為O(n),但是每次增長為倍數,push_back的平均時間複雜度為O(1)

2.那若是增長因子大於2倍呢?會存在空間浪費的情況,而且等於兩倍或1.5倍可以重複使用之前申請過的記憶體。

4樓:zzkluck

這裡補充一點:儘管看起來每次擴容都需要拷貝全部元素是一項很大的開銷,但我們依舊能保證,在平攤分析的視角下,插入操作是O(1)的。所以效能其實還好。

這裡有份詳細的證明,https://

b23.tv/BV1Tb411M7FA/p13

5樓:海鵬

為什麼不先判斷尾元素之後的記憶體空間是否滿足擴容後的需求

標準庫沒有原地擴容否則失敗的函式,標準庫的realloc是嘗試原地擴容,否則新開闢一塊,然後memcpy

memcpy是不對的,應該呼叫拷貝構造,所以用不了realloc

6樓:暮無井見鈴

這個問題涉及的內容有點多…

我們應該明確這點: C++ 標準庫容器的動態記憶體分配是交予分配器(Allocator)類處理的。

[allocator.requirements]

故而分配器提供什麼介面,標準庫容器的記憶體操作才能用什麼。從 C++98 至今標準庫的分配器要求都缺少原位擴張/收縮的介面,所以 vector/basic_string 也用不了。

實際上有 N3495 、P0401 、 P0894 等零星提案建議增加分配器的介面,以支援這些功能。

另一方面,即使上述增強分配器的設計進入標準庫,容器所用的預設分配器 std::allocator 也不一定能從中受益。原因是 std::

allocator 的 allocate 與 deallocate 分別包裝全域性的分配函式 ::operator new 與解分配函式 ::operator delete ,這些函式是 C++ 語核所要求的,而且可以被使用者替換。

這使得目前不一定有機制使 std::allocator 支援原位收縮/擴張或自動重新分配。

來自 C 的 realloc 是個對於 C++ 相當不靈活的函式:

realloc 有可能原地收縮/擴張,但也會靜默地重新分配記憶體,使用者無法選擇。部分原因可能是有些 realloc 的會重新對映虛擬位址,而非原位擴張失敗後再次分配。

realloc 分配的記憶體只保證擁有基礎對齊。 C11/C++17 具有對齊記憶體分配函式, realloc 卻沒有乙個處理對齊的增強版本。

目前 C++ 的物件模型還不允許直接把非可平凡複製的型別的物件逐位移動到另乙個位置,同時將原位置的物件視為已死亡。有兩個提案 P1029 和 P1144 建議修改 C++ 物件模型以支援這類操作。兩者的具體手段有點小區別。

(另一方面 Rust 物件模型支援這種設計,而且這類物件非常常見。)

需要注意的是即使進行了物件模型的修改,有些型別仍然不支援這種逐位移動(譬如有自引用的型別)。

考慮到以上問題, realloc 本身可能不太適合適配到泛型的分配器中。不過類似的靜默重分配功能(有可能利用虛擬位址的重對映)可以作為乙個可選的功能,是否使用取決於 vector 的元素型別。 basic_string 的元素型別必須是 POD ,所以不會遇到物件模型的問題。

最後補充一下, C++11 起 push_back 需要分配新記憶體時一般都是把元素移動構造過去,而非複製構造。

7樓:MashPlant

你的想法是有一定道理的,為什麼大家都在一味的批判呢?

可以看一下這個問題下的回答:

比起malloc new/free old,realloc(重新分配記憶體)在效能上有多少的優勢?

(例如我的回答:

比起malloc new/free old,realloc(重新分配記憶體)在效能上有多少的優勢?

8樓:Glavo

首先,vector 的記憶體是用作為模板引數提供的 allocator 分配的,而不是 malloc, realloc 只能處理 malloc/calloc/realloc 分配的記憶體(雖然預設的 allocator 最底層一般還是用 malloc 分配的記憶體,但 C++ 層未必能知道),而 allocator 也沒有提供對應的的功能。

其次,vector 使用 malloc 分配記憶體的情況下,realloc 也只能在值型別是 trivially copyable 的情況下才能使用,因為 realloc 在沒法直接在原位址分配記憶體的情況下會直接 free 掉原本的記憶體並拷貝值,非 trivially copyable 的物件根本不能這樣拷貝。

另外 vector 本身已經保留了一定的容量起到類似的效果,可以用 capacity 方法檢視分配的大小。

9樓:於無聲處

如果你是想說,vector在擴充記憶體時,為什麼不正好在尾巴上分一塊,這樣就接上了。那麼答案是vector辦不到,它只能向記憶體分配器說「我想要多大多大的空間」,不能要求這塊空間一定在指定的位置。

10樓:月色血風暴

最直觀,簡單來看,因為它的尾部記憶體空間可能已經被占用了,所以要先另外開闢一塊較大的空間,再拷貝過去。

一般要用push_back之前先用reserve申請你可能用到的最大的記憶體,就不會引起重新分配釋放了。

也可以先resize,再通過取下標給元素賦值,最後再resize一次將多餘的元素釋放掉。自己測試這種方法比push_back效率更高。

11樓:Michael

這個我覺你要考慮一下,在尾元素後面申請記憶體很有可能是不成功的,因為後面的資料可能已經分配給別人用了啊,那c++的vector肯定是不知道後面記憶體的資訊的。只有系統知道,很顯然讓編譯器和作業系統在這一方面達成一致不是一件高效的事,不管從哪個方面來說。

C vector容器和list容器的插入和隨機讀寫有限制,標準庫有沒有不限制的呢?

nekosu 僅就你說的需求的話,deque基本可以滿足。這裡提一下為什麼標準庫不弄乙個full featured的容器。每乙個容器所暴露出來的功能都是在複雜度優秀的,這樣可以讓使用者對其消耗的時間有數。如果什麼操作都支援,幾乎必然會有部分操作的複雜度會高於另外幾個,這在效率很重要的C 中是難以接受...

好的好的好的好的好的好的好的?

首席鏟屎官 早熟的果子大都青澀。個人經歷分享 經歷過高中戀愛,也經歷過大學戀愛,最終在研究生期間尋找到了最合適的人和最穩定的相處模式。男生這種行為不論是出於羞澀,還是有其他陰謀詭計,都說明,他還不是乙個成熟的個體,不是乙個好的選項。 追憶似水流年 先來潑點冷水吧,說點你不想聽的事實 1 乙個男生經常...

筆記本的的的的電腦配置?

齊河一家 你說的用途都可以,據說這個CPU發熱大,可以退而求I5 7300HQ也便宜 吃雞可以在1080P效果下開低效,或者降成900P開中高效 牧野 琳 其他3項完全OK。PUBG需要調教。這種配置能執行,不過高畫質就別想了。優先保障穩定60FPS再去考慮畫質。有必要弄乙個風扇底座架空機器,確保底...