迭代器失效規則

C ++容器的迭代器失效規則是什麼? 算法

最好是摘要列表格式。 數組

(注意:這原本是Stack Overflow的C ++ FAQ的條目。若是您想批評以這種形式提供FAQ的想法,那麼在全部這些開始的meta上的張貼將是這樣作的地方。該問題在C ++聊天室中進行監控,該問題最初是從FAQ想法開始的,因此提出這個想法的人極可能會讀懂您的答案。) 安全


#1樓

可能值得補充的是,只要全部插入都是經過此迭代器執行的,而且沒有其餘獨立的迭代器無效,則任何類型的插入迭代器( std::back_insert_iteratorstd::front_insert_iteratorstd::insert_iterator )均可以保證保持有效。事件發生。 less

例如,當您經過使用std::insert_iteratorstd::vector執行一系列插入操做時,這些插入頗有可能會觸發向量從新分配,這將使「指向」該向量的全部迭代器失效。 可是,能夠保證所涉及的插入迭代器保持有效,即,您能夠安全地繼續插入序列。 徹底沒必要擔憂觸發向量從新分配。 函數

一樣,這僅適用於經過插入迭代器自己執行的插入。 若是迭代器無效事件是由對容器的某些獨立操做觸發的,則插入迭代器也將根據常規規則變爲無效。 spa

例如,此代碼 指針

std::vector<int> v(10);
std::vector<int>::iterator it = v.begin() + 5;
std::insert_iterator<std::vector<int> > it_ins(v, it);

for (unsigned n = 20; n > 0; --n)
  *it_ins++ = rand();

即便向量「決定」在此過程的中間從新分配,也能夠確保對向量執行有效的插入序列。 迭代it顯然會變得無效,但it_ins將繼續保持有效。 code


#2樓

因爲這個問題吸引了不少票,而且成爲了一種常見問題,因此我認爲最好寫一個單獨的答案來說起C ++ 03和C ++ 11在std::vector的影響方面的一個顯着差別。相對於reserve()和Capacity capacity()的迭代器和引用有效性的插入操做,最受支持的答案未能引發注意。 orm

C ++ 03: 對象

從新分配會使全部引用序列中元素的引用,指針和迭代器無效。 確保在調用reserve()以後發生的插入期間不會發生從新分配,直到插入使向量的大小大於最近對reserve()的調用中指定的大小爲止。

C ++ 11:

從新分配會使全部引用序列中元素的引用,指針和迭代器無效。 能夠保證在調用reserve()以後直到插入使向量的大小大於Capacity()的值以前,在插入期間不會發生從新分配。

所以,在C ++ 03中,正如在另外一個答案中提到的那樣,它不是「 unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated) 」,而是應「 greater than the size specified in the most recent call to reserve() 。 這是C ++ 03與C ++ 11不一樣的一件事。 在C ++ 03中,一旦insert()使得向量的大小達到上一個reserve()調用中指定的值(該值可能會小於當前的capacity()由於reserve()可能會致使更大的值)。 capacity()超出要求),任何後續insert()均可能致使從新分配並使全部迭代器和引用無效。 在C ++ 11中,這種狀況不會發生,您能夠始終信任capacity()來肯定在大小超過Capacity capacity()以前不會進行下一次從新分配。

總之,若是您使用的是C ++ 03向量,而且要確保在執行插入操做時不會發生從新分配,則應該檢查大小,這是先前傳遞給reserve()的參數的值反對,而不是對capacity()的返回值,不然您可能會對「 過早 」的從新分配感到驚訝。


#3樓

C ++ 17 (全部參考均來自CPP17的最終工做草案-n4659


插入

序列容器

  • vector :功能insertemplace_backemplacepush_back緣由從新分配,若是新的尺寸比舊容量。 從新分配會使全部引用序列中元素的引用,指針和迭代器無效。 若是沒有發生從新分配,則插入點以前的全部迭代器和引用均保持有效。 [26.3.11.5/1]
    關於reserve功能,從新分配會使全部引用序列中元素的引用,指針和迭代器無效。 在對reserve()的調用以後發生的插入過程當中,直到插入使向量的大小大於capacity()的值以前,都不得進行從新分配。 [26.3.11.3/6]

  • deque :在deque的中間插入會使全部迭代器和對雙端隊列的元素的引用無效。 在雙端隊列的任一端插入將使該雙端隊列的全部迭代器無效,但不會影響對雙端隊列的元素的引用的有效性。 [26.3.8.4/1]

  • list :不影響迭代器和引用的有效性。 若是引起異常,則沒有效果。 [26.3.10.4/1]。
    insertemplace_frontemplace_backemplacepush_frontpush_back功能是在本規則覆蓋。

  • forward_listinsert_after的重載均不影響迭代器和引用的有效性[26.3.9.5/1]

  • array一般 ,數組的迭代器在數組的整個生命週期內都不會失效。 可是,應該注意的是,在交換期間,迭代器將繼續指向同一數組元素,所以將更改其值。

關聯容器

  • All Associative Containersinsertemplace成員不該影響迭代器和對該容器的引用的有效性[26.2.6 / 9]

無序關聯容器

  • All Unordered Associative Containers :從新哈希將使迭代器無效,更改元素之間的順序以及更改出如今存儲桶中的元素,但不會使對元素的指針或引用無效。 [26.2.7 / 9]
    insertemplace成員不該影響對容器元素的引用的有效性,但可使對容器的全部迭代器無效。 [26.2.7 / 14]
    若是(N+n) <= z * B ,則insertemplace成員不影響迭代器的有效性,其中N是插入操做以前容器中元素的數量, n是插入元素的數量, B是容器的存儲桶計數, z是容器的最大裝載係數。 [26.2.7 / 15]

  • All Unordered Associative Containers :在合併操做(例如a.merge(a2) )的狀況下,引用已傳輸元素的迭代器和引用a全部迭代器都將無效,但保留在a2元素的迭代器將保持有效。 (表91 —無序關聯容器要求)

容器適配器

  • stack :從基礎容器繼承
  • queue :從基礎容器繼承
  • priority_queue :從基礎容器繼承

清除

序列容器

  • vector :函數erasepop_back使擦除點或擦除點以後的迭代器和引用無效。 [26.3.11.5/3]

  • deque :即一個擦除的最後一個元素的擦除操做deque無效信號僅在過去的最末端迭代器和全部迭代器和引用擦除元素。 擦除deque的第一個元素而不擦除最後一個元素的擦除操做僅會使迭代器和對已擦除元素的引用無效。 不擦除deque的第一個元素或最後一個元素的擦除操做會使過去的迭代器和全部迭代器以及對deque全部元素的引用無效。 [注意: pop_frontpop_back是擦除操做。 —尾註] [26.3.8.4/4]

  • list :僅使迭代器和對已刪除元素的引用無效。 [26.3.10.4/3]。 這適用於erasepop_frontpop_backclear函數。
    removeremove_if成員函數:擦除列表迭代器i引用的列表中的全部元素,並知足如下條件: *i == valuepred(*i) != false 。 僅使迭代器和對已刪除元素的引用無效[26.3.10.5/15]。
    unique成員函數-擦除迭代器i引用的每一個連續連續的相等元素組中除第一個元素外的全部元素,範圍爲[first + 1, last) ,其中*i == *(i-1) (對於不帶參數的惟一值)或pred(*i, *(i - 1)) (對於帶謂詞參數的不重複版本)成立。 僅使迭代器和對已擦除元素的引用無效。 [26.3.10.5/19]

  • forward_listerase_after將僅使迭代器和對已擦除元素的引用無效。 [26.3.9.5/1]。
    removeremove_if成員函數-擦除列表迭代器i所引用的列表中的全部元素,並知足如下條件: *i == value (對於remove() ), pred(*i)爲true(對於remove_if() )。 僅使迭代器和對已擦除元素的引用無效。 [26.3.9.6/12]。
    unique成員函數-擦除迭代器i所引用的每一個連續連續的相等元素組中除第一個元素外的全部元素,範圍爲[first + 1,last],其中*i == *(i-1) (對於具備沒有參數)或pred(*i, *(i - 1)) (對於帶有謂詞參數的版本)成立。 僅使迭代器和對已擦除元素的引用無效。 [26.3.9.6/16]

  • All Sequence Containersclear會使引用a元素的全部引用,指針和迭代器無效,而且可能使過去的迭代器無效(表87-序列容器要求)。 可是對於forward_listclear不會使過去的迭代器無效。 [26.3.9.5/32]

  • All Sequence Containersassign使全部引用容器元素的引用,指針和迭代器無效。 對於vectordeque ,還會使過去的迭代器無效。 (表87-序列容器要求)

關聯容器

  • All Associative Containerserase成員應僅使迭代器和對已擦除元素的引用無效[26.2.6 / 9]

  • All Associative Containersextract成員僅使刪除元素的迭代器無效; 指向被刪除元素的指針和引用仍然有效[26.2.6 / 10]

容器適配器

  • stack :從基礎容器繼承
  • queue :從基礎容器繼承
  • priority_queue :從基礎容器繼承

與迭代器失效有關的常規容器要求:

  • 除非另有說明(顯式指定或經過在其餘函數中定義一個函數),不然調用容器成員函數或將容器做爲參數傳遞給庫函數均不得使對該容器內對象的迭代器或更改其值無效。 [26.2.1 / 12]

  • 沒有swap()函數會使引用被交換容器的元素的任何引用,指針或迭代器無效。 [注意:end()迭代器未引用任何元素,所以可能無效。 —尾註] [26.2.1 /(11.6)]

做爲上述要求的示例:

  • transform算法: opbinary_op函數不得使迭代器或子範圍無效,或修改範圍[28.6.4 / 1]中的元素

  • accumulate算法:在[first,last]範圍內, binary_op既不得修改元素,也不得使迭代器或子範圍無效[29.8.2 / 1]

  • reduce算法:binary_op既不該使迭代器或子範圍無效,也不得修改[first,last]範圍內的元素。 [29.8.3 / 5]

等等...


#4樓

C ++ 03 (來源: 迭代器無效規則(C ++ 03)


插入

序列容器

  • vector :插入點以前的全部迭代器和引用均不受影響,除非新的容器大小大於先前的容量(在這種狀況下,全部迭代器和引用均無效)[23.2.4.3/1]
  • deque :全部迭代器和引用均無效,除非插入的成員位於雙端隊列的末尾(這種狀況下,全部迭代器均無效,但對元素的引用不受影響)[23.2.1.3/1]
  • list :全部迭代器和引用均不受影響[23.2.2.3/1]

關聯容器

  • [multi]{set,map} :全部迭代器和引用均不受影響[23.1.2 / 8]

容器適配器

  • stack :從基礎容器繼承
  • queue :從基礎容器繼承
  • priority_queue :從基礎容器繼承

清除

序列容器

  • vector :擦除點以後的每一個迭代器和引用都無效[23.2.4.3/3]
  • deque :全部迭代器和引用都無效,除非被刪除的成員位於雙端隊列的末端(先後)(在這種狀況下,僅迭代器和對被刪除成員的引用都無效)[23.2.1.3/4]
  • list :僅迭代器和對已擦除元素的引用無效[23.2.2.3/3]

關聯容器

  • [multi]{set,map} :僅迭代器和對已刪除元素的引用無效[23.1.2 / 8]

容器適配器

  • stack :從基礎容器繼承
  • queue :從基礎容器繼承
  • priority_queue :從基礎容器繼承

調整大小

  • vector :按照插入/擦除[23.2.4.2/6]
  • deque :按照插入/擦除[23.2.1.2/1]
  • list :按插入/擦除[23.2.2.2/1]

注1

除非另有說明 (顯式指定或經過在其餘函數中定義一個函數),不然調用容器成員函數或將容器做爲參數傳遞給庫函數均不得使對該容器內對象的迭代器或更改其值無效 。 [23.1 / 11]

筆記2

在C ++ 2003中,尚不清楚「結束」迭代器是否受上述規則約束 ; 不管如何,您都應該假設它們是實際狀況(實際狀況就是如此)。

注3

指針無效的規則與引用無效的規則相同。


#5樓

C ++ 11 (來源: 迭代器無效規則(C ++ 0x)


插入

序列容器

  • vector :插入點以前的全部迭代器和引用均不受影響,除非新的容器大小大於先前的容量(在這種狀況下,全部迭代器和引用均無效)[23.3.6.5/1]
  • deque :全部迭代器和引用都無效,除非插入的成員位於雙端隊列的末尾(這種狀況下,全部迭代器均無效,但對元素的引用不受影響)[23.3.3.4/1]
  • list :全部迭代器和引用均不受影響[23.3.5.4/1]
  • forward_list :全部迭代器和引用均不受影響(適用於insert_after [23.3.4.5/1]
  • array :(不適用)

關聯容器

  • [multi]{set,map} :全部迭代器和引用均不受影響[23.2.4 / 9]

未分類的關聯容器

  • unordered_[multi]{set,map} :從新進行哈希處理時,全部迭代器均無效,但引用不受影響[23.2.5 / 8]。 若是插入不會致使容器的大小超過z * B ,則不會進行從新哈希處理,其中z是最大裝載因子, B是當前的存儲桶數。 [23.2.5 / 14]

容器適配器

  • stack :從基礎容器繼承
  • queue :從基礎容器繼承
  • priority_queue :從基礎容器繼承

清除

序列容器

  • vector :擦除點或擦除點以後的每一個迭代器和引用都無效[23.3.6.5/3]
  • deque :刪除最後一個元素只會使迭代器無效,而且對已刪除元素和過去的迭代器的引用無效; 擦除第一個元素只會使迭代器和對已擦除元素的引用無效; 刪除任何其餘元素會使全部迭代器和引用(包括過去的迭代器)無效[23.3.3.4/4]
  • list :僅迭代器和對已擦除元素的引用無效[23.3.5.4/3]
  • forward_list :只有迭代器和引用到擦除元件被無效(適用於erase_after )[23.3.4.5/1]
  • array :(不適用)

關聯容器

  • [multi]{set,map} :僅迭代器和對已刪除元素的引用無效[23.2.4 / 9]

無序關聯容器

  • unordered_[multi]{set,map} :僅迭代器和對已刪除元素的引用無效[23.2.5 / 13]

容器適配器

  • stack :從基礎容器繼承
  • queue :從基礎容器繼承
  • priority_queue :從基礎容器繼承

調整大小

  • vector :按照插入/擦除[23.3.6.5/12]
  • deque :按照插入/擦除[23.3.3.3/3]
  • list :按插入/擦除[23.3.5.3/1]
  • forward_list :按照插入/擦除[23.3.4.5/25]
  • array :(不適用)

注1

除非另有說明 (顯式指定或經過在其餘函數中定義一個函數),不然調用容器成員函數或將容器做爲參數傳遞給庫函數均不得使對該容器內對象的迭代器或更改其值無效 。 [23.2.1 / 11]

筆記2

沒有swap()函數會使引用被交換容器的元素的任何引用,指針或迭代器無效 。 [注意: end()迭代器沒有引用任何元素,所以它多是無效的 。 —尾註] [23.2.1 / 10]

注3

除了上述關於swap()注意事項外, 尚不清楚「結束」迭代器是否受以上列出的每一個容器規則約束 ; 不管如何,您應該假設它們是。

注4

vector和全部無序關聯容器都支持reserve(n) ,這保證至少在容器大小增加到n以前,不會自動調整大小。 應謹慎對待無序的關聯容器,由於未來的建議將容許指定最小加載因子,這將容許在足夠的erase操做將容器尺寸減少到最小如下以後在insert進行從新哈希處理; erase後,該擔保應被視爲可能無效。

相關文章
相關標籤/搜索