![](/img/trans.png)
[英]Does pop_back() really invalidate *all* iterators on an std::vector?
[英]Why does vector::pop_back invalidate the iterator (end() - 1)?
erase
。 見底部。 在vector
上調用pop_back
之后, end() - 1
迭代器無效的事實背后的原因是什么?
為了澄清,我指的是這種情況:
std::vector<int> v;
v.push_back(1);
v.push_back(2);
std::vector<int>::iterator i1 = v.begin(), i2 = v.end() - 1, i3 = v.begin() + 1;
v.pop_back();
// i1 is still valid
// i2 is now invalid
// i3 is now invalid too
std::vector<int>::iterator i4 = v.end();
assert(i2 == i4); // undefined behavior (but why should it be?!)
assert(i3 == i4); // undefined behavior (but why should it be?!)
為什么會這樣? (即,這種失效何時將證明對實施有利?)
(請注意,這不僅是理論上的問題。如果您將_ITERATOR_DEBUG_LEVEL
設置為2
,則在嘗試以調試模式執行此操作時,Visual C ++ 2013-可能還有2012-也會顯示錯誤。)
erase
: 請注意,相同的問題也適用於erase
:
為什么erase(end() - 1, end())
使end() - 1
無效?
(因此,請不要說“ pop_back
使end() - 1
無效,因為它等效於調用erase(end() - 1, end())
” ;這只是在問這個問題。)
有趣的問題是,使迭代器無效意味着什么。 而且我的標准確實沒有很好的答案。 我所知道的是,在某種程度上,該標准將迭代器視為不是指向容器內部位置的指針,而是作為駐留在容器中的特定元素的代理。
考慮到這一點,在刪除向量中間的單個元素之后,移除點之后的所有迭代器都將變得無效,因為它們不再引用之前引用的相同元素。
對這種推理的支持來自容器中其他操作的迭代器無效子句。 例如,在insert
,該標准保證,如果沒有重新分配,則插入點之前的迭代器仍然有效。 例外情況 , 在插入點之后 ,它將使所有迭代器無效。
如果迭代器的有效性僅與容器中存在迭代器所指向的元素有關,則該操作都不會使迭代器無效(同樣,在沒有重新分配的情況下)。
進一步講,如果您將迭代器有效性視為指針有效性 ,則在erase
操作期間,向量中的所有迭代器都不會失效。 end()-1
迭代器將變得不可取,但可以保持有效,事實並非如此。
pop_back
通常是用pop_back
erase(end()-1, end())
。
當您從向量中擦除一定范圍的迭代器時,從第一個被擦除和向前擦除的所有迭代器都將失效。 這包括一個范圍。
通常,有效的不可重新引用的非輸入迭代器始終引用相同的數據“位置”,直到無效為止。 在erase
的情況下,之后所有非無效的迭代器當前都具有相同的值和位置。
上面兩個規則都必須進行修改才能獲得所需的行為。 第一個類似“除非您這樣做會刪除最后一個元素,在這種情況下,第一個被刪除的元素將成為最后一個迭代器”。 而且仍然有效的迭代器將變得不可取,據我所知,對於迭代器而言,這可能是唯一的狀態更改,在C ++中尚無先例。
成本既是標准中用來支付您要求的行為的額外技巧,又是嚴格的迭代器的健全性檢查。 好處-好吧,我看不到:在每種情況下,您都必須確切地知道發生了什么(一個非常特殊的迭代器只是在末尾成為一個迭代器而不是被無效),如果您知道是這種情況,只能說說end
。
並且需要單詞。 當你調用erase( a, b )
從每一個迭代a
上都會有其狀態以某種方式改變( *a
不會返回相同的值,以及如何必須指定的更改)。 C ++采取了簡單的方法,只是聲明其狀態被erase
更改的每個迭代器都將變為無效,並且使用它是未定義的行為:這允許實現者獲得最大的自由度。
從理論上講,它還可以進行優化。 如果在erase
操作之前和之后取消引用迭代器,則可以認為您獲得的值是相同的! (假設不可能在對象析構函數內對容器進行間接修改,這也可以被證明)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.