1

I got terminate called after throwing an instance of 'std::bad_alloc' when trying to push an additional string to a middle of a vector. I used g++ 4.8.2.

I even got output with wrong vector sizes size of str_vector 0: 1, size of str_vector 1: 1 when using g++ 5.2 on coliru.

The program works correctly when I use index (e.g., str_vector[0]) to access vectors or use std::list.

Does this mean there is some restriction on the use of iterator? I assume that there should not any difference when I use index or iterator to access vectors.

#include <iostream>
#include <string>
#include <vector>

using std::vector;
using std::string;

int main() {
        vector<vector<string>> str_vector;

        str_vector.emplace_back();
        vector<vector<string>>::iterator it0 = std::prev(str_vector.end());
        it0->push_back("a");

        str_vector.emplace_back();
        vector<vector<string>>::iterator it1 = std::prev(str_vector.end());
        it1->push_back("a");

        it0->push_back("a"); // bad alloc here

        std::cerr << "size of str_vector 0: " << it0->size() << std::endl;
        std::cerr << "size of str_vector 1: " << it1->size() << std::endl;

        return 0;
}
Duke
  • 1,154
  • 10
  • 11
  • Pretty much every implementation of the standard library has a compiler option that provides diagnostics. Enable those and try again. The `bad_alloc` is just a symptom caused by undefined behaviour of your code. – Ulrich Eckhardt Oct 04 '15 at 13:18
  • What is that iterator needed for anyway? I've never seen someone use an iterator for `push_back`. – Damon Oct 04 '15 at 14:30
  • I wanted to have references to each inner vector in the vector. Thereby, I can add strings to each inner vector on the fly. – Duke Oct 05 '15 at 01:21

2 Answers2

3

When you add elements to a vector it might need to reallocate its internal memory, which leads to all iterator to become invalid. So after you do the second emplace_back the first iterator it0 becomes invalid.

Some programmer dude
  • 363,249
  • 31
  • 351
  • 550
  • Is using vector indexes, which are not invalidated after pushes, the only viable option to get a reference to each inner vector? I wanted to add strings to each inner vector on the fly. – Duke Oct 05 '15 at 01:30
1

Iterators are nothing but object oriented pointers. Iterator invalidation is a lot like pointer invalidation.

C++ Spec:

vector: all iterators and references before the point of insertion are unaffected, unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated) [23.2.4.3/1]

First time you execute the below line, it's valid.Second time you do it with the same iterator, the iterator has already been invalidated:

    it0->push_back("a"); // bad alloc here

For knowing what iterator invalidation is and how to handle it , there is this excellent post on iterator invalidation here:

[Iterator invalidation rules

Community
  • 1
  • 1
basav
  • 1,355
  • 10
  • 19