[英]How to use vector iterators when using vector<>::push_back()
為了簡單起見,我將堅持使用vector<int>
但是我認為這適用於任何vector<T>
對象。
如果我使用vector<int>::iterator
跟蹤int向量中的某個位置,然后使用vector<int>::push_back()
,則迭代器變得一文不值。 意思是,我不能使用&
取消引用它的地址。 一旦我按以下含義打印了某些對象的地址,便會找到直接原因:
vector<int> my_vec(1); //my_vec[0] = 0
vector<int>::iterator it = my_vec.begin(); //it -> my_vec[0], *it = my_vec[0] = 0
cout << "&my_vec = " << &my_vec << "\n";
cout << "&my_vec[0] = " << &my_vec[0] << "\n";
cout << "&it = " << &it << "\n"; //prints address, all good
cout << "*it = " << *it << "\n"; //prints 0, all good
cout << "\n\n" << pushing back..." << "\n\n";
my_vec.push_back(1);
cout << "&my_vec = " << &my_vec << "\n"; //same as before push_back()!
cout << "&my_vec[0] = " << &my_vec[0] << "\n"; //different from before push_back()!!
cout << "&it = " << &it << "\n"; //same as before push_back()
//cannot do &it or *it
因此,顯然it
的地址沒有改變,但是push_back()
在內存中移動了東西,現在my_vec
的不同“元素”的my_vec
也發生了變化。 my_vec [i]具有新地址這一事實對我來說很有意義,但隨后我有以下問題:
1)為什么my_vec
的地址my_vec
更改? 看來,如果push_back()
導致my_vec[i]
的地址發生更改,它也應該更改整個對象的地址。 對於數組, my_array
是指向my_array[0]
的指針,因此我可以想象一個操作,該操作將更改每個my_array[i]
的地址並更新該指針以指向my_array[0]
的新地址,但指向my_array
指針的地址作為一個對象本身就不會改變。 但是my_vec
在任何意義上都不是指向my_vec[0]
的指針,因此我感到困惑,為什么my_vec[i]
的地址會更改,但對象my_vec
不會更改。
2)為什么vector<int>
內部的任何更改my_vec[i]
地址的my_vec[i]
(例如push_back()
)也不能正確地“更新”任何迭代器? 這似乎是個好主意? 沒有?
3)既然它是#2,並且當我調用push_back()
時我的迭代器變得一文不值,處理此問題的正確方法是什么? 如果需要使用push_back()
是否應該不使用迭代器? 如果有人要抱怨使用迭代器和push_back()
用例是什么,我為簡潔起見就將其排除在外,但它基本上是使用vector<int>
實現堆棧的,而我使用的是迭代器來跟蹤頂部的堆棧。 由於我不希望以固定的大小開始,因此當迭代器命中my_vec.end()
時,我嘗試使用push_back()
擴大堆棧。 但我認為這通常是一個有效的問題。
非常感謝您的幫助!
為什么
my_vec
的地址my_vec
更改?
因為矢量對象本身仍然是同一地址的同一對象。 重新分配會更改其管理的動態數組的地址,而不是管理該數組的矢量對象的地址。
為什么
vector<int>
內部的任何更改my_vec[i]
地址的my_vec[i]
(例如push_back()
)也不能正確地“更新”任何迭代器? 這似乎是個好主意? 沒有?
那會帶來(也許很大)的運行時成本。 向量要么必須跟蹤所有迭代器(需要動態存儲,每次創建迭代器時都要分配內存,並且在向量更改時更新所有向量),要么每個迭代器都需要引用容器,並在每次訪問時進行檢查,並且不能實現為簡單的指針。 C ++通常會在可能的情況下避免運行時成本,尤其是在這種情況下,這種情況幾乎總是不必要的。
解決這個問題的正確方法是什么?
有多種選擇。 您可以存儲索引而不是迭代器。 您可以使用帶有穩定迭代器的std::list
類的容器(盡管效率可能較低)。 如果可以在數組的大小上設置上限,則可以保留該數量,以便不需要重新分配。 您可以編寫自己的容器(或適配器)來自動更新迭代器。 對於您的堆棧,如果確實是一個堆棧,則不需要跟蹤向量的末尾,因此根本不需要存儲迭代器。 或者您可以使用std::stack
而不是重新發明它。
是否有其他
vector<T>
成員函數(除了顯而易見的成員函數)對迭代器有影響?
當任何操作導致向量超出其當前容量時,迭代器將因重新分配而無效。 您可以使用reserve
功能控制容量。
同樣,擦除元素會使引用被擦除元素或序列中后續元素的任何迭代器無效。
為什么my_vec的地址沒有更改?
std::vector
中內存的重新分配發生在其內部緩沖區中,該緩沖區保存其元素而不是對象本身(即,不是std::vector
本身)。 考慮以下玩具示例:
template<typename T>
class vector {
T *buffer;
...
public:
...
};
如果我定義了一個vector
對象(例如, vector<int> v
),則對象v
具有一個地址。 當由於插入或擦除而發生重新分配時,更改的不是v
的地址,而是其成員變量buffer
的值(即, buffer
將指向新的地址位置)。
為什么vector內部的任何更改my_vec [i]地址的操作(例如push_back())也不能正確地“更新”任何迭代器?
迭代器無效的問題是眾所周知的,在必須處理此類情況時應采取預防措施。
是否還有其他矢量成員函數(除了明顯的成員函數之外)會對迭代器產生影響? 它取決於T嗎?
是的,有(例如std::vector::insert
, std::vector::erase
)。 不,它不依賴於T
(即std::vector
元素的類型)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.