4

I was trying to insert few values from a vector to that same vector object but it seems to have erred:

#include<iostream>
#include<vector>

using namespace std;

int main()
{
    vector<int> vec;
    for(int i=0;i<9;i++)
    {
        vec.push_back(i+1);
    }

    vec.insert(vec.begin(),vec.begin()+2,vec.end()-4);  //PROBLEM
    vector<int>::iterator ivec=vec.begin();
    while(ivec!=vec.end())
    {
        cout<<*ivec<<' ';
        ++ivec;
    }
    cout<<endl;
    return 0;
}

I am expecting that elements from vec.begin()+2 i.e. 3 to element vec.end()-4 i.e. 6 are inserted in the vector. But the output is:

3 1 2 1 2 3 4 5 6 7 8 9

Compiler is g++ 4.1.2. Where am I wrong in this?

Agrudge Amicus
  • 1,033
  • 7
  • 19
  • 1
    [Why is using namespace std; considered bad practice?](https://stackoverflow.com/q/1452721) – L. F. Jun 17 '19 at 10:26
  • 2
    If there’s an allocation all iterators are invalid, at least. Also related: https://stackoverflow.com/questions/14820835/does-stdvectorinsert-invalidate-iterators-if-the-vector-has-enough-room-c – Sami Kuhmonen Jun 17 '19 at 10:30
  • I believe, it is U.B. because: `std::vector::insert()` may cause reallocation. A reallocation in turn may invalidate all current iterators. If I'm right, inserting a vector with values from itself is a bad idea. – Scheff's Cat Jun 17 '19 at 10:30
  • 1
    I encourage you to consider what `insert` would have to do in order to make this work. – chris Jun 17 '19 at 10:30
  • 1
    This question the subject of ongoing discussion on Meta: https://meta.stackoverflow.com/q/386172/8239061 – SecretAgentMan Jun 18 '19 at 16:24

2 Answers2

9

The problem is that when you start inserting elements you invalidate any existing iterators to that vector, including the iterators that specify the range you are trying to insert. Simple solution is to copy the slice of the vector you want to insert first.

 vector<int> tmp(vec.begin() + 2, vec.end() - 4);
 vec.insert(vec.begin(), tmp.begin(), tmp.end());
john
  • 85,011
  • 4
  • 57
  • 81
4
vec.insert(vec.begin(),vec.begin()+2,vec.end()-4);

Here, you pass to insert the iterators to the container itself. This is not allowed because of iterator invalidation.

Per [tab:container.req.seq]:

 a.insert(p,i,j)

Expects: T is Cpp17EmplaceConstructible into X from *i. For vector and deque, T is also Cpp17MoveInsertable into X, Cpp17MoveConstructible, Cpp17MoveAssignable, and swappable ([swappable.requirements]). Neither i nor j are iterators into a.

Effects: Inserts copies of elements in [i, j) before p. Each iterator in the range [i, j) shall be dereferenced exactly once.

Therefore, the behavior is undefined.

L. F.
  • 19,445
  • 8
  • 48
  • 82