I do not understand why this code is accurate
vector<int> coll;
coll.reserve(2*coll.size());
copy (
coll.begin(), coll.end(), // zrodlo
back_inserter(coll) // przeznaczenie
);
coll.end()
represents the end of vector. After I push_back anything (as back_insert_iterator
does) what coll.end()
returns is the same what was before or something different? Are there more than one terminating iterator? Why end() can be use as an end of container even when new content is added?
Moreover, you cannot apply the code to list container - it gets stuck. That is important because in case of vector push_back makes iterators unreliable after reallocating data (when size()==capacity()
and push_back()
called) whereas in case of list that's not the case. Than why the code hangs for list?
Edit: (sscce)
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
template <class T>
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
typename T::const_iterator pos;
std::cout << optcstr;
for (pos=coll.begin(); pos!=coll.end(); ++pos) {
std::cout << *pos << ' ';
}
std::cout << std::endl;
}
int main(){
list<int> coll;
list<int>::iterator end = coll.end();
copy (
coll.begin(), coll.end(), // zrodlo
back_inserter(coll) // przeznaczenie
);
cout << *end << endl;
PRINT_ELEMENTS(coll);
}
the begin()
and end()
pointers/iterators used to determine what is to be copied are evaluated once when the function is called. So essentially std::copy()
will increment it's cursor iterator which will eventually reach end()
, because vector<T>::const_iterator
is just a fancy T*
pointer on an old school array.
As you correctly mentionned, if a push_back
makes the vector
reallocate and move the data somewhere else in memory, then the next element copied will have a wrong address for source, which is likely to end up with a segmentaion fault.
For a list, it can never terminate because end()
is a sentinel/guard pointer, and you can only reach end()
by incrementing the iterator on the last element of the list. So the address of end()
itself never changes, but because you are constantly adding an element at the end of the list, you will never reach the last element, so std::copy()
can never obtain a pointer to end()
. Kind of like a dog chasing it's tail.
It's easier to understand with illustrations and diagrams, read-up on doubly linked list and sentinel nodes, it will all make sense.