容器作為引用傳參可能導致迭代器失效
一、序列型容器
包括vector,deque,string
等,其特點是元素儲存在連續記憶體中,插入和刪除會導致之後的元素移動,所以插入和刪除都會導致插入/刪除點及其之後的所有迭代器失效。
在迴圈中刪除元素的正確寫法:
for
(auto it = nums.
begin()
; it != nums.
end();
)if(.
..) it = nums.
erase
(it)
;// erase返回下乙個有效的迭代器
else
++it;
二、關聯型容器
包括map,set,unordered_set
等,其特點是使用紅黑樹來儲存元素,插入不會使任何迭代器失效,刪除會使指向刪除點的那乙個迭代器失效,其餘不會失效。
在迴圈中刪除元素的正確寫法:
for
(auto it = map.
begin()
; it != map.end;)if
(...
) map.
erase
(it++);
else it++
;
在c++ 98中,erase不會返回下乙個有效的迭代器,但在c++ 11標準中則會。因此,在新標準裡it = map.erase(it)
也是可行的。
三、鏈表型容器
包括list
等,其特點是元素儲存在不連續的記憶體中,插入不會使任何迭代器失效,刪除會使指向刪除點的那乙個迭代器失效,其餘不會失效。
在迴圈中刪除元素的正確寫法:
for
(auto it = list.
begin()
; it != list.end;)if
(...
) list.
erase
(it++);
//或者 it = list.erase(it)
else it++
;
總結
需要通過迭代器一邊遍歷一邊刪除元素時,一定不能直接讓迭代器遞增,it = stl.erase(it)
適用於新標準中這3種型別的容器,stl.erase(it++)
適用於關聯型和鏈表型容器。
今天在做leetcode第46題全排列時,我實現了回溯演算法,但**一直遇到段錯誤,如下:
class solution
private:
void
dfs(vectorint>>
& result, vector<
int>
& permutation, list<
int>
& l)
for(
auto it = l.
begin()
; it != l.
end();
)}};
gdb顯示段錯誤發生在這兩行:
dfs
(result, permutation, l);l.
insert
(it, tmp)
;
雖然我在迴圈中刪除和插入鍊錶的元素,但我的寫法是正確的,不會導致迭代器的失效。我另外編寫了一段測試**,證明了這樣寫是沒問題的,那麼問題出在哪就令人百思不得其解了。
最終發現是由於list& l
的&
導致的。我本來想利用引用傳參來節省記憶體和時間,畢竟執行完乙個dfs函式之後鍊錶中的元素是沒有變化的,但它卻導致了迭代器的失效。
以l=[1,2]
為例,按**中的邏輯,先要刪除1,此時it
指向2,l=[2]
傳入下一層dfs。在下一層dfs執行時,會刪除掉這個2,由於l
是引用的,這個刪除操作導致了上一層dfs中的it
失效,儘管之後會將2插入到原位置,看起來l
中的元素沒有變化,但迭代器已經發生了改變。此時返回上一層dfs,再用it
去插入元素,自然會引發段錯誤。
C 引用 和指標在作為形參時的區別
nt n int m n 在c 中,多了乙個c語言沒有的引用宣告符 如上,m就是n的引用,簡單的說m就是n的別名,兩者在記憶體中佔同樣的位置,不對m開闢新的記憶體空間,對m的任何操作,對n來說是一樣的。對於引用,有以下三條規則 1 引用被建立的同時必須被初始化 指標則可以在任何時候被初始化 2 不能...
C 引用 和 指標 在作為形參時的區別
一 熱身準備 int n int m n 在c 中,多了乙個c語言沒有的引用宣告符 如上,m就是n的引用,簡單的說m就是n的別名,兩者在記憶體中佔同樣的位置,不對m開闢新的記憶體空間,對m的任何操作,對n來說是一樣的。二 對於引用,有以下三條規則 1 引用被建立的同時必須被初始化 指標則可以在任何時...
std中list作為常量傳參時乙個迭代器錯誤
如果list作為常量引數傳入函式時,使用list的迭代器要注意,如果 這樣寫 ostream operator ostream ostr,const list li return ostr error conversion from std list const iterator to non sc...