Vector Objects - Maintaining Pointers?

Jan 25, 2010 at 10:40pm
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 :)
Jan 25, 2010 at 10:46pm
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.
Jan 25, 2010 at 10:53pm
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?
Jan 25, 2010 at 10:56pm
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 Jan 25, 2010 at 10:57pm
Jan 25, 2010 at 11:09pm
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!
Jan 25, 2010 at 11:27pm
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]; 
}
Jan 25, 2010 at 11:27pm
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.
Jan 25, 2010 at 11:40pm
Great, thanks very much to both of you.

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