0

Consider the following code:

#include <iostream>
#include <vector>

using namespace std;

class SomeClass {
public:
    SomeClass(int num) : val_(num) {}
    int val_;
    int val() const { return val_; }
};

// Given a vector of vector of numbers, this class will generate a vector of vector of pointers
// that point to SomeClass.
class Generator {
public:
    vector<SomeClass> objects_;
    vector<vector<SomeClass*> > Generate(const vector<vector<int> >& input) {
        vector<vector<SomeClass*> > out;
        for (const auto& vec : input) {
            out.push_back({});
            for (const int num : vec) {
                SomeClass s(num);
                objects_.push_back(s);
                out.back().push_back(&objects_.back());
            }
        }
        return out;
    }
};

int main() {
    Generator generator;
    auto output = generator.Generate({{2, 3}, {4, 5}, {6}});
    for (const auto& vec : output) {
        for (const auto* obj : vec) {
            printf("%d ",obj->val());
        }
        printf("\n");
    }
    return 0;
}

The Generate method in the Generator class will simply convert the vector of vector of ints to a vector of vector of pointers to SomeClass.

SomeClass is simply a container for a simple int value with a getter method.

I would expect the following output:

2 3
4 5
6

However, I get the following output:

junk_integer junk_integer
4 5
6

It seems the pointers in the first row become dangling pointers. What is wrong with this code?

Palec
  • 12,743
  • 8
  • 69
  • 138
Gowtham
  • 101
  • 1
  • When `objects_` resizes to allow pushing back new elements, can you guess what happens to all of the existing pointers? – user4581301 Mar 26 '17 at 04:41
  • 1
    Possible duplicate of [What happen to pointers when vectors need more memory and realocate memory?](http://stackoverflow.com/questions/8261037/what-happen-to-pointers-when-vectors-need-more-memory-and-realocate-memory) – user4581301 Mar 26 '17 at 04:44
  • You want an array of pointers to what kind of objects? Are these heap objects or stack objects? If the former, what part of the code is responsible for their allocation and deletion? If the latter, when do these objects go out of scope? Is there a possibility a pointer will live longer than the object it points to? These are questions you *must* answer when you create a pointer. – n. m. could be an AI Mar 26 '17 at 05:45

3 Answers3

1

You're storing pointers into a vector, then adding elements to the vector. Since you're not reserving enough space for all the elements you're adding, when the vector resizes it invalidates all the pointers to the old data.

You'll either have to reserve enough space before storing the pointers, store the pointers after you've stored everything in the vector you need to store, or not store pointers (maybe store an index, instead).

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
1

All operations that increase the number of elements in a std::vector, including push_back(), invalidates all iterators (including pointers) that refer to elements of the vector, if the resizing results in a change of vector capacity.

Your code is doing

objects_.push_back(s);
out.back().push_back(&objects_.back());

within a loop. Every call of objects_.push_back() invalidates iterators of objects_, and therefore can result in out.back() containing invalid (dangling) pointers.

Peter
  • 35,646
  • 4
  • 32
  • 74
0

You are storing pointers to objects contained in generator.objects_. Some of them become dangling pointers when you call push_back() on that.

In general, storing pointers to objects in a std::vector is a bad idea.

R Sahu
  • 204,454
  • 14
  • 159
  • 270