Is an Iterator to vec.end() still valid after vec.push_back() when there is no reallocation
Is this example code valid?
#include<vector>
using namespace std;
int main() {
vector<int> vec(10); // create with 10 elements
vec.reserve(100); // set capacity to 100
vector<int>::iterator iter = vec.end(); // points 1 past vec[9]
vec.push_back( 777 );
bool is_this_valid_and_true = *iter == vec[10]; // ?
// VS2010 runtime error in debug build:
// Expression: vector iterator not dereferencable
// Works in release build
iter = vec.end() + 1; // points 2 past vec[10]?
vec.push_back( 888 );
vec.push_back( 999 );
is_this_valid_and_true = *iter == vec[12]; // ?
}
The error in VS2010 may be related to this bug.
If I set the command line option /D_HAS_ITERATOR_DEBUGGING=0
or set
#define _HAS_ITERATOR_DEBUGGING 0
#include<vector>
there is no error.
Edit:
In light of the answers, I think this code should cause an error. There is no bu开发者_高级运维g in the compiler. It only works in release mode because iterators are implemented as pointers.
23.2.4.3/1:
Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor or assignment operator of T there are no effects.
So no, end()
doesn't have to be valid after push_back
. The quote is in relation to vector.insert
, push_back
is defined in terms of insert
You are thinking of iterators as pointers.
Iterators may use pointers as an implementation detail but they are not actual pointers.
Thus:
iter = vec.end() + 1; // This is not valid.
There is no such thing as two elements passed the end of data.
vec.end() returns an iterator that when decrement is a reference to the last elements (assuming there are elements). While an iterator referencing the last element when incremented is equivalent to the iterator returned by end().
// Note: Assuming vector iterators were not invalidated after an insert anyway.
// But for arguments sake lets play this out.
//
vector<int>::iterator iter = vec.end(); // points 1 past vec[9]
vec.push_back( 777 );
bool is_this_valid_and_true = *iter == vec[10]; // Not valid.
// This is the end() iterator
// de-referencing it is UB
But de-referenceing the iterator representing by end() is undefined behavior() (even if you have reserved space) (the implementation may not be using pointers. For example some of the DeBug STL implementations will do extensive error checking in the iterator code).
精彩评论