gsgx
gsgx

Reputation: 12249

How to store pointers to statically allocated objects in a vector?

Lets say I wanted to make a vector of objects and another vector of pointers to those objects (I cannot use dynamic memory). The way I would do it is in the following example.

#include <iostream>
#include <vector>

using namespace std;

class Foo {
public:
  int bar;
  Foo(int x) : bar(x) {
  }
};

int main () {
  vector<Foo> foos;
  vector<Foo*> pFoos;
  for (int i = 0; i < 10; i++) {
    Foo foo(i);
    foos.push_back(foo);
    pFoos.push_back(&foos.back());
  }

  for (int i = 0; i < 10; i++) {
    cout << foos[i].bar << endl;
    cout << pFoos[i]->bar << endl;
  }
}

I think this should work because foos stores a copy of the object, and then I store the reference to the copy (because the original foo will be undefined, so I shouldn't store a reference to that). But this is what I get:

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

The first to numbers from pFoos are wrong. Furthermore, the large number changes every time. I don't see anything that would cause this undefined behavior. Could someone tell me what I'm doing wrong?

Upvotes: 0

Views: 151

Answers (3)

mythagel
mythagel

Reputation: 1839

Adding items to a vector invalidates all previous iterators. Calling push_back on the vector may make the pointers you got from it previously invalid if the vector needs to reallocate its internal storage.

If you knew that you were never going to grow the vector again then this would work:

for (int i = 0; i < 10; i++) {
  foos.push_back(Foo(i));
}

for (int i = 0; i < 10; i++) {
  pFoos.push_back(&foos[i]);
}

or as commented by rodrigo:

foos.reserve(10)

for (int i = 0; i < 10; i++) {
  Foo foo(i);
  foos.push_back(foo);
  pFoos.push_back(&foos.back());
}

for (int i = 0; i < 10; i++) {
  cout << foos[i].bar << endl;
  cout << pFoos[i]->bar << endl;
}

Upvotes: 8

Pete Becker
Pete Becker

Reputation: 76498

vector::push_back can move elements, which is why the addresses aren't valid. You can pre-load the memory for the vector to its final size by calling reserve before you start pushing things into the vector, or you can wait until you've finished pushing things before you take their addresses.

But you say that you "cannot use dynamic memory". vector uses dynamic memory.

Upvotes: 1

Roozbeh Zabihollahi
Roozbeh Zabihollahi

Reputation: 7347

I guess this is not a good programming approach. The vector is responsible for storing objects and it may REALLOC memory to get bigger memory blobs ... So, your pointer is not valid anymore ...

Upvotes: 2

Related Questions