簡體   English   中英

使用vector <> :: push_back()時如何使用向量迭代器

[英]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::insertstd::vector::erase )。 不,它不依賴於T (即std::vector元素的類型)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM