简体   繁体   English

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

[英]How to use vector iterators when using vector<>::push_back()

For simplicity, I'll stick to vector<int> but I think this applies to any vector<T> object. 为了简单起见,我将坚持使用vector<int>但是我认为这适用于任何vector<T>对象。

If I am using a vector<int>::iterator to keep track of some position in a vector of int's and then I use vector<int>::push_back() , the iterator becomes worthless. 如果我使用vector<int>::iterator跟踪int向量中的某个位置,然后使用vector<int>::push_back() ,则迭代器变得一文不值。 Meaning, I can't take its address with & or dereference it. 意思是,我不能使用&取消引用它的地址。 The direct reason made sense once I printed the address of some of the objects in the following sense: 一旦我按以下含义打印了某些对象的地址,便会找到直接原因:

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

So obviously the address of it doesn't change but push_back() has moved things around in memory and now the address of the different "elements" of my_vec are changed. 因此,显然it的地址没有改变,但是push_back()在内存中移动了东西,现在my_vec的不同“元素”的my_vec也发生了变化。 The fact that my_vec[i] has a new address made sense to me but then I have the following questions: my_vec [i]具有新地址这一事实对我来说很有意义,但随后我有以下问题:

1) Why doesn't the address of my_vec change? 1)为什么my_vec的地址my_vec更改? It seems that if push_back() causes the addresses of the my_vec[i] to change, it should also change the address of the whole object. 看来,如果push_back()导致my_vec[i]的地址发生更改,它也应该更改整个对象的地址。 For an array, my_array is a pointer to my_array[0] so I can imagine an operation changing the addresses of each my_array[i] and updating the pointer to point to the new address of my_array[0] but the address of the pointer my_array as an object in and of itself wouldn't change. 对于数组, my_array是指向my_array[0]的指针,因此我可以想象一个操作,该操作将更改每个my_array[i]的地址并更新该指针以指向my_array[0]的新地址,但指向my_array指针的地址作为一个对象本身就不会改变。 But my_vec is not a pointer in any sense to my_vec[0] so I am confused why the addresses of the my_vec[i] would change but not the object my_vec . 但是my_vec在任何意义上都不是指向my_vec[0]的指针,因此我感到困惑,为什么my_vec[i]的地址会更改,但对象my_vec不会更改。

2) Why would any operation internal to vector<int> that changes the address of the my_vec[i] (such as push_back() ) not also properly "update" any iterators? 2)为什么vector<int>内部的任何更改my_vec[i]地址的my_vec[i] (例如push_back() )也不能正确地“更新”任何迭代器? This seems like a good idea? 这似乎是个好主意? No? 没有?

3) Given that #2 is what it is and my iterators become worthless when I call push_back() , what is the correct way to deal with this? 3)既然它是#2,并且当我调用push_back()时我的迭代器变得一文不值,处理此问题的正确方法是什么? Should I not use iterators if I need to use push_back() ? 如果需要使用push_back()是否应该不使用迭代器? If someone is going to complain about what my use-case is for using iterators and push_back() , I excluded it for brevity but it was basically implementing a stack using vector<int> and I was using an iterator to keep track of the top of the stack. 如果有人要抱怨使用迭代器和push_back()用例是什么,我为简洁起见就将其排除在外,但它基本上是使用vector<int>实现堆栈的,而我使用的是迭代器来跟踪顶部的堆栈。 Since I didn't want a fixed size to start, I tried to use push_back() to enlarge the stack when my iterator hit my_vec.end() . 由于我不希望以固定的大小开始,因此当迭代器命中my_vec.end()时,我尝试使用push_back()扩大堆栈。 But I think this is a valid question in general. 但我认为这通常是一个有效的问题。

Thanks very much for your help! 非常感谢您的帮助!

Why doesn't the address of my_vec change? 为什么my_vec的地址my_vec更改?

Because the vector object itself is still the same object at the same address. 因为矢量对象本身仍然是同一地址的同一对象。 Reallocation changes the address of the dynamic array that it manages, not the vector object that manages the array. 重新分配会更改其管理的动态数组的地址,而不是管理该数组的矢量对象的地址。

Why would any operation internal to vector<int> that changes the address of the my_vec[i] (such as push_back() ) not also properly "update" any iterators? 为什么vector<int>内部的任何更改my_vec[i]地址的my_vec[i] (例如push_back() )也不能正确地“更新”任何迭代器? This seems like a good idea? 这似乎是个好主意? No? 没有?

That would have a (perhaps large) runtime cost. 那会带来(也许很大)的运行时成本。 Either the vector would have to track all the iterators (requiring dynamic storage, memory allocation each time an iterator is created, and updating of all vectors when the vector changes) or each iterator would need a reference to the container, checked on every access, and could not be implemented as a simple pointer. 向量要么必须跟踪所有迭代器(需要动态存储,每次创建迭代器时都要分配内存,并且在向量更改时更新所有向量),要么每个迭代器都需要引用容器,并在每次访问时进行检查,并且不能实现为简单的指针。 C++ generally avoids runtime costs where possible - especially in cases like this, where they are nearly always unnecessary. C ++通常会在可能的情况下避免运行时成本,尤其是在这种情况下,这种情况几乎总是不必要的。

what is the correct way to deal with this? 解决这个问题的正确方法是什么?

There are various options. 有多种选择。 You could store an index rather than an iterator. 您可以存储索引而不是迭代器。 You could use a container such as std::list with stable iterators (although that might be rather less efficient). 您可以使用带有稳定迭代器的std::list类的容器(尽管效率可能较低)。 If you can place an upper bound on the size of the array, you could reserve that amount so that reallocation won't be necessary. 如果可以在数组的大小上设置上限,则可以保留该数量,以便不需要重新分配。 You could write your own container (or adapter) that automatically updates iterators. 您可以编写自己的容器(或适配器)来自动更新迭代器。 For your stack, if it is indeed a stack, you shouldn't need to track anything other than the end of the vector, so there's no need to store an iterator at all. 对于您的堆栈,如果确实是一个堆栈,则不需要跟踪向量的末尾,因此根本不需要存储迭代器。 Or you could use std::stack rather than reinventing it. 或者您可以使用std::stack而不是重新发明它。

Are there any other vector<T> member functions (besides the obvious ones) that have this effect on iterators? 是否有其他vector<T>成员函数(除了显而易见的成员函数)对迭代器有影响?

Iterators are invalidated by reallocation, when any operation causes the vector to grow beyond its current capacity. 当任何操作导致向量超出其当前容量时,迭代器将因重新分配而无效。 You can control the capacity with the reserve function. 您可以使用reserve功能控制容量。

Also, erasing elements will invalidate any iterator referring to the erased elements, or elements later in the sequence. 同样,擦除元素会使引用被擦除元素或序列中后续元素的任何迭代器无效。

Why doesn't the address of my_vec change? 为什么my_vec的地址没有更改?

A reallocation of memory in a std::vector happens to its internal buffer that holds its elements and not the object itself (ie, not the std::vector itself). std::vector中内存的重新分配发生在其内部缓冲区中,该缓冲区保存其元素而不是对象本身(即,不是std::vector本身)。 Consider the following toy example: 考虑以下玩具示例:

template<typename T>
class vector {
  T *buffer;
  ...
public:
  ...
};

If I define a vector object (eg, vector<int> v ), the object v has an address. 如果我定义了一个vector对象(例如, vector<int> v ),则对象v具有一个地址。 When a reallocation happens due to an insertion or an erasure it's not the address of v that changes but rather the value of its member variable buffer (ie, buffer would point to a new address location). 当由于插入或擦除而发生重新分配时,更改的不是v的地址,而是其成员变量buffer的值(即, buffer将指向新的地址位置)。

Why would any operation internal to vector that changes the address of the my_vec[i] (such as push_back()) not also properly "update" any iterators? 为什么vector内部的任何更改my_vec [i]地址的操作(例如push_back())也不能正确地“更新”任何迭代器?

The issue of iterator invalidation is well known and you should take your precautions when you have to deal with such situations. 迭代器无效的问题是众所周知的,在必须处理此类情况时应采取预防措施。

Are there any other vector member functions (besides the obvious ones) that have this effect on iterators? 是否还有其他矢量成员函数(除了明显的成员函数之外)会对迭代器产生影响? Does it depend on T? 它取决于T吗?

Yes there are (eg, std::vector::insert , std::vector::erase ). 是的,有(例如std::vector::insertstd::vector::erase )。 No it doesn't depend on T (ie, the type of the std::vector 's element). 不,它不依赖于T (即std::vector元素的类型)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM