Vector Objects - Maintaining Pointers?

How can one maintain a pointer to an object within a vector even when the vector will be resized often? Is there a good way to do this?

To be more specific, I have the following struct:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct AI::reality{
	vector<AI::object> object;
	
	reality(int size=10){ object.reserve(size); }
	~reality(){}
	
	AI::object * NewObject(){
		object.push_back(AI::object());
		return &object[object.size()-1];}
			
	AI::object * AddObject(AI::object NewObject){
		object.push_back(NewObject);
		return &object[object.size()-1];}
};


Now I'd like to be able to do something like this:
1
2
3
4
5
6
7
AI::reality WORLD(1);
AI::object *chair1, *chair2;
chair1 = WORLD.AddObject(chair);
chair2 = WORLD.AddObject(chair);

chair1->blah();
chair2->blah();


But this obviously does not work, since the chair1 pointer will be invalidated when the "object" vector in WORLD has to resize to make room for chair2.

Is there anything I could place in the AI::reality class that would allow me to maintain pointers to the object instances in the vector WITHOUT using indices (I'd rather be able to access objects directly, not through WORLD.object[index].)?

Reserving a huge block and counting on the vector not resizing is not an option.

Thanks in advance :)
There's no way with the vector declared like that. You'd need to declare the vector as an std::vector<T *>, and allocate the objects dynamically. Then you can pass around pointers to the objects with the certainty that they'll remain valid even if the vector gets reallocated.
Ah thanks, good idea. I messed around with using pointers a bit and came up with this, which seems to work:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct AI::reality{
	vector<AI::object> object;
	vector<AI::object **> objptr;
	
	reality(int size=10){ object.reserve(size); }
	~reality(){}
		
	void AddObject(AI::object ** pointer, AI::object NewObject){
		object.push_back(NewObject);
		objptr.push_back(pointer);
		for ( int i = 0; i < int(object.size()); ++i ){ (*objptr[i]) = &object[i];}
		return; }
};


Now the double-pointer objptr vector stores a pointer to the pointer passed into AddObject so that it can modify the external pointer to correctly point to each element of the object vector after resizing.

I can create an object like so
1
2
3
4
5
6
7
AI::reality WORLD(1);
AI::object *chair1, *chair2;
WORLD.AddObject(&chair1,chair);
WORLD.AddObject(&chair2,chair);

chair1->blah();
chair2->blah();


However, I am sure that I have probably broken some rules in doing this because I am still rather new with memory, vectors, and even pointers. Are there any "bad practice" things in this class? I am creating memory leaks?
That's still wrong.
1
2
3
4
5
6
	vector<AI::object> object;
//...
	AI::object * AddObject(AI::object &NewObject){
		this->object.push_back(new AI::object(NewObject))
		return this->object.back();
	}

Of course, you'll have to destruct the objects later on with delete.
Last edited on
Helios,

Thanks very much, that works as well. I have a few more questions, if you don't mind.

1) Why do you pass NewObject as a reference? Does it save you from a copy constructor call?
2) Why do you use this-> to get to the current reality's vars instead of saying object.push_back directly?
3) ~reality(){ for ( int i = 0; i < int(object.size()); ++i ) delete object[i]; }
Is this a correct destructor?

Again, thanks for you help!
1.) Basically.
2.) It's more explicit, if you had a global variable called object (would be stupid to have but still), it would be hard to tell which one you would get
3.) Don't cast .size() to an int, use this a size_type for i instead (or unsigned int/size_t if you are lazy):
1
2
3
~reality(){ 
    for ( std::vector<AI::object>::size_type i = 0; i < object.size(); ++i ) delete object[i]; 
}
1) Exactly. Otherwise there'd be copy for passing the parameter and another copy for constructing the dynamic object.

2) That's my style. Without the explicit this-> it looks too ambiguous for my taste.

3) That should work, but if you make i of type size_t, you won't need the cast to int in the condition.
Great, thanks very much to both of you.

All questions solved :)
Topic archived. No new replies allowed.