Multimap Dilemma

Started by
1 comment, last by Zahlman 16 years, 9 months ago
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. Alright after that I have where you can add a model.

void AddModel(std::string name, std::string file)
{
    Model temp.LoadObj(file);
    SceneModels.insert(name, -1, temp); //-1 denotes that it has no parent
}
Alright, the dilemma lies here, I am trying to make one object a parent of another object like so:

void MakeParent(std::string parent, std::string child)
{
    std::multimap<std::string, int, Model>::iterator it;
    std::multimap<std::string, int, Model>::iterator it2;
    it = SceneModels.find(parent);
    it2 = SceneModels.find(child);
    it2->second = //????
}
The first iterator finds the "parent" identity of a Model. The second iterator finds the "child" identity of a Model. Now, when trying to set the Parent ID of "child" I am stuck because I don't know how to find what index you are currently at with an iterator like this.
Advertisement
In your example, the first element of the multimap iterator is the key, which in your case represents your int index. The second element of the iterator represents the actual object stored at this location.
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.

This topic is closed to new replies.

Advertisement