[英]Don't understand iterator, reference and pointer invalidation, an example
我已經閱讀了很多關於引用、指針和迭代器失效的帖子。 例如,我讀到插入會使對雙端隊列元素的所有引用無效,那么為什么在下面的代碼中我沒有錯誤?
#include <deque>
int main()
{
std::deque<int> v1 = { 1, 3, 4, 5, 7, 8, 9, 1, 3, 4 };
int& a = v1[6];
std::deque<int>::iterator it = v1.insert(v1.begin() + 2, 3);
int c = a;
return a;
}
當我運行它時,我得到 9 結果,所以“a”仍然指的是正確的元素。 一般來說,我沒有設法得到失效錯誤。 我嘗試了不同的容器,甚至使用指針和迭代器。
以下代碼在我的系統上顯示了未定義行為的影響。
#include <deque>
#include <iostream>
int main()
{
std::deque<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (auto e : v1) std::cout << e << ' ';
std::cout << std::endl;
int& a = v1[1];
int& b = v1[2];
int& c = v1[3];
std::cout << a << ' ' << b << ' ' << c << std::endl;
std::deque<int>::iterator it = v1.insert(v1.begin() + 2, -1);
for (auto e : v1) std::cout << e << ' ';
std::cout << std::endl;
v1[7] = -3;
std::cout << a << ' ' << b << ' ' << c << std::endl;
return a;
}
它對我的輸出是:
1 2 3 4 5 6 7 8 9 10
2 3 4
1 2 -1 3 4 5 6 7 8 9 10
-1 3 4
如果引用a
、 b
和c
仍然有效,則最后一行應該是
2 3 4
請不要由此推斷a
已失效而b
和c
仍然有效。 他們都是無效的。
試試看,也許你很“幸運”,它向你展示了同樣的東西。 如果沒有,請嘗試使用容器中的元素數量和一些插入。 在某些時候,也許你會看到一些奇怪的東西,就像我的情況一樣。
附錄
std::deque
的實現方式都使失效機制比“更簡單”的std::vector
更復雜一些。 而且您也沒有多少方法來檢查某些東西是否真的會受到未定義行為的影響。 例如,使用std::vector
,您可以判斷未定義的行為是否會刺痛您push_back
; 實際上,您有成員函數capacity
,它告訴容器是否已經有足夠的空間來容納通過push_back
插入更多元素所需的更大size
。 例如,如果size
為 8, capacity
為 10,您可以“安全地” push_back
兩個元素。 如果再推一次,則必須重新分配陣列。
有時,可能會使某些內容無效的操作不會。
我對 std::deque 實現不夠熟悉,無法發表評論,但如果你在 std::vector 上執行 push_back,你可能會使所有迭代器、引用和指向向量元素的指針失效,例如,因為 std::vector 需要分配更多內存來容納新元素,並最終將所有數據移動到新位置,在那里該內存可用。
或者,您可能沒有任何無效的東西,因為向量有足夠的空間來在適當的位置構建一個新元素,或者幸運地在其當前內存位置的末尾獲得足夠的新內存,而不必移動任何東西,而仍然改變了大小。
通常,文檔會仔細記錄哪些操作會使哪些操作無效。 例如,在https://en.cppreference.com/w/cpp/container/deque 中搜索“無效”。
此外,標准數據結構的特定實現可能比標准保證更安全 - 但依賴它會使您的代碼高度不可移植,並且當不言而喻的安全保證發生變化時可能會引入隱藏的錯誤:一切似乎都可以正常工作直到它沒有。
唯一安全的做法是仔細閱讀規范,不要依賴不能保證的東西不會失效。
此外,正如 Enrico 指出的那樣,您可能會遇到引用/指針/迭代器失效的情況,但從它們中讀取會產生一個看起來不錯的值,因此這種用於測試某些內容是否已失效的簡單方法是行不通的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.