Jas Jas - 14 days ago 5
C++ Question

C++ map vector reference error

I am getting a program crash from the following code:

// declaration in header:
std::vector<Animation> mAnimations; // animation objects
std::map<std::string, Animation*> mBoneAnimations; // map strings to animation objects from "mAnimations"

// source code in source file:
this->mAnimations.push_back(Animation());
this->mBoneAnimations[bone_name] = &this->mAnimations.back();
// ...
// at different points, we modify the LAST element in animation
this->mAnimations.back().addTranslation(Vector3(...));

// this is where the problem occurs later on in the program:
Animation test = *(this->mBoneAnimations.at("Body")); // CRASH


This code crashes on the last line. I am 80% sure that this problem is caused by the way I have set this data structure up. My guess was that maybe getting the reference to the last object in the vector using "back()" might be causing this. I tried changing it to:

this->mBoneAnimations[bone_name] = &this->mAnimations[this->mAnimations.size() - 1];


But this did not help either. The question is what causes this crash and more specifically, how can I fix it?

Edit: I am sure that there is a "Body" object in there. This crash is a memory error.

Answer

When you append to a std::vector, it sometimes has to reallocate. When it does that, it moves all of its elements to a new location in order to keep the elements in contiguous memory. This invalidates all pointers, references and iterators, so mBoneAnimations is storing dangling pointers.

So long as you only ever push/pop to the back/front, a quick fix would be to use std::deque instead. When you push_back to a deque and run out of space, instead of reallocating all the elements, it just adds a new block of elements, leaving the old ones where they were. (see section on iterator validity). Same for push front and pop.