簡體   English   中英

向量分配會使`reserve`無效嗎?

[英]Does a vector assignment invalidate the `reserve`?

假設我寫

std::vector<T> littleVector(1);
std::vector<T> bigVector;

bigVector.reserve(100);
bigVector = littleVector;

標准是否說bigVector仍將保留100個元素? 還是要push_back 99個元素,我會遇到內存重新分配的情況? 也許甚至在STL實現之間也有所不同。

之前已在此處進行了討論但未提供標准參考。

不幸的是,該標准沒有充分說明分配器感知序列容器分配的行為,並且確實嚴格地說是不一致的。

從表28和23.2.1p7中我們知道,如果allocator_traits<allocator_type>::propagate_on_container_copy_assignment::valuetrue則在復制分配時替換分配器。 此外,從表96和99中,我們發現副本分配的復雜度線性的 ,並且操作a = t后置條件a == t ,即(表96) distance(a.begin(), a.end()) == distance(t.begin(), t.end()) && equal(a.begin(), a.end(), t.begin()) 從23.2.1p7開始,在復制分配之后,如果分配器傳播,則a.get_allocator() == t.get_allocator()

關於矢量容量,23.3.6.3 [vector.capacity]具有:

5- 注釋:重新分配會使引用序列中元素的所有引用,指針和迭代器無效。 可以保證在調用reserve()直到插入使向量的大小大於capacity()的值之前,在插入期間不會發生重新分配。

如果我們以庫DR341作為閱讀標准的指南:

但是,第23.3.6.3 [vector.capacity]段5的措詞可以防止在調用reserve()之后向量的容量減少。 這使成語無效,因為這樣可以防止swap()減少容量。 [...]

DR341通過在23.3.6.3中添加以下段落來解決:

void swap(vector<T,Allocator>& x);
7- 效果:*this的內容和capacity()x交換。
8- 復雜度:固定時間。

結論是,從圖書館委員會的角度來看,如果僅在23.3.6.3中提及,則操作只能修改Capacity capacity() 在23.3.6.3中未提及副本分配,因此不會修改Capacity capacity() (移動分配具有相同的問題,尤其是考慮到對庫DR2321的建議分辨率。)

顯然,這是標准中的缺陷,因為復制分配傳播的不相等分配器必須導致重新分配,這與23.3.6.3p5相矛盾。

我們可以期望並希望通過以下措施解決此缺陷:

  • 非分配器修改副本分配上的非減少capacity()
  • 分配器修改副本分配上未指定的Capacity capacity()
  • 非分配器傳播的移動分配上的非減少capacity()
  • 分配器傳播的移動分配上的source-container capacity()

但是,在當前情況下,除非弄清楚這一點,否則您最好不要依賴任何特定行為。 幸運的是,有一個簡單的解決方法可以保證不減少capacity()

bigVector.assign(littleVector.begin(), littleVector.end());

對於標准容器,對operator=的唯一要求是之后,如表96(在23.2,通用容器要求中)所指定的那樣, src == dst 此外,該表還指定了operator ==的含義:

distance(lhs.begin(), lhs.end()) == distance(rhs.begin(), rhs.end()) // same size
  && equal(lhs.begin(), lhs.end(), rhs.begin()) // element-wise equivalent

請注意,這不包含任何容量。 除了一般不變的capacity() >= size()之外,標准的其他任何部分也沒有提及容量。 因此,分配后的容量值未指定,只要保持分配器要求,容器就可以隨意執行其希望的分配方式。


通常,您會發現實現的行為使得

  • 如果分配器比較相等並且dst有足夠的容量,它將保留其舊存儲,
  • 否則,它將為新元素分配足夠的存儲空間,並且
  • 在任何情況下都不會關心src的容量。

當然,移動分配是另外一個故事。 由於通常是通過竊取源存儲來實現的,因此也會占用容量。

這取決於分配器特征。

這是摘錄自http://en.cppreference.com/w/cpp/container/vector/operator%3D

如果std :: allocator_traits :: propagate_on_container_copy_assignment()為true,則將目標分配器替換為源分配器的副本。 如果目標分配器與源分配器的比較不相等,則使用目標分配器(* this)分配內存,然后在復制元素之前使用Other的分配器分配內存。(自C ++ 11起)

基本上,如果分配器不兼容(如果它們不能釋放彼此的內存,則使用新的分配器重新分配內存)。

向量實現之間無關緊要,分配器實現之間沒有關系(這很有意義)。

暫無
暫無

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

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