Quote:Original post by Niddles
Hello, I'm trying to improve my scene graph and I am trying to use multimap. The multimap is:
std::multimap<std::string, int, Model> SceneModels;
Is this the correct format of constructing a multimap?
The string is to identify which model it is, the int is the index of the element in the multimap that is the parent of the current model.
No, nowhere near. I'm not sure what you think a std::multimap does, so let's recap: it's just like a std::map, except that multiple values could be associated with a given key. So there are only two template parameters that you would want to use here. (Additional parameters are possible, but they serve completely different purposes: you can specify the way in which keys are compared, and the way in which memory is allocated. Both of these are advanced usages that you probably aren't interested in.)
There *are no* "indices of elements"; you look up into the container *by key*. There is no int that you could store that makes sense.*
I think what you want to do is use an ordinary std::map, where the *value* consists of "the key for the parent model, plus the current model". We can stick two things together like this by making a struct (or by just adding the "string parentName;" to the model struct), or by using a convenient helper from the standard library: std::pair.
With the std::pair approach, it would look like this:
// We'll use a typedef for the map's type so that we aren't constantly typing// such an unwieldy thing; and to make the code easier to maintain.typedef std::map<std::string, std::pair<std::string, Model> > ModelTree;ModelTree SceneModels;void AddModel(const std::string& modelName, const std::string& fileName) { // What you had here before was nonsense: // Model temp.LoadObj(file); // You can't call a member function on something in the same breath that you // declare it. You *can* use a *constructor* though, and that's exactly what // you should be doing with your Model objects - don't make 'load' functions, // but instead use RAII: Model temp(fileName); // Here, an empty string denotes "no parent". SceneModels[modelName] = std::make_pair("", temp);}bool MakeParent(const std::string& parent, const std::string& child) { // Again, initialize things with their first value when you can. // Iterators included. :) ModelTree::iterator pit = SceneModels.find(parent); ModelTree::iterator cit = SceneModels.find(child); // We should check that we actually found both things. if (pit == SceneModels.end() || cit == SceneModels.end()) { return false; } // Now, the ->second of each iterator yields the pair (not a pointer to it), // so ->second.first is the "parent name" field of the value, while ->first // is the key. cit->second.first = pit->first; return true; }
* Well, you could store the std::distance() between the map's .begin() and the current iterator, but that would be *very dangerous*: the number would potentially become garbage as soon as anything is added or removed from the map. It would also be disgustingly inefficient to try to use that number to find an element: the map is *designed for* looking things up by key.