2

So I am trying to set an unordered_map as value for another unordered_map. Now I have the problem that I am not able to put values into the second unordered_map. My code looks like this.

  std::string postCode;
  std::string[] postCodeSource = new std::string{1111,2222,3333,4444};
  std::unordered_map<std::string,unordered_map<int,Foo*>*> data;
  int k1=1234;//can be any number
  for(int i = 0; i < 4; i++){
    postCode = postCodeSource[i]
    if(data[postCode]==NULL) {
      data[postCode]=new std::unordered_map<int,Foo*>();
    }
    data[postCode]->at(int(k1)) = new Foo(postCodeSource[i]);
  }

classes:

class Foo{
  public:
  Foo();
  Foo(std::string postCode);
  std::string firstName,Customername,postCode;
}

Foo(std::string postCode); is a simple copy constructor.

Now when I reach data[lastPlz.getString()]->at(int(k1.customer)) = new Foo(&k1); I get an out of range exception from unordered_map which makes sense since there is no object at k1.customer yet! Before I changed the code I created and filled a pointer looking like that.

std::unordered_map<int,Foo*> kdnrMap
kdnrMap[k1.customer] = new Foo(&k1);

and later on, I added kdnrMap to data. That won't work anymore the way I intended since this method would need a completely filled kdnrMap before I can add it to data which I can't do anymore.

So I am looking for help to get kdnrMap filled I've tried pretty much anything I could think of for now.

10
  • 1
    There is so much code that is missing here. A minimal reproducible example would probably make this simple to solve. Commented Feb 19, 2020 at 15:22
  • 1
    Foo, Foo2; a minimal example that actually compiles. We could probably tease your problem out of your text description, but that is needlessly complicated and ambiguous. Just write some simple code that demonstrates your problem. Commented Feb 19, 2020 at 15:25
  • 1
    Please note that operator[] is quite expensive, you better use it only once unless it is really necessary to use it multiple times. You as your map seems to have ownership of the data you better use smart pointers. Commented Feb 19, 2020 at 15:25
  • 1
    Btw why do you need to store inner map as a pointer? Just to make your code more complicated and error prone? Commented Feb 19, 2020 at 15:28
  • 1
    Then you are making it not only more complicated but a bit slower as another unnecessary indirection would be involved. Guess where std::unordered_map stores its data? Commented Feb 19, 2020 at 15:51

1 Answer 1

2

You don't really need to store the inner map as a pointer. Just let the outer map own the inner one like this:

std::unordered_map<std::string,
   std::unordered_map<int, std::unique_ptr<Foo>>> data;
data[postCode][int(k1.Kundennr)] = new Foo(&k1);

I advise against using raw pointers here, since there is a high risk of leaking memory if you replace a value in the inner map. Using std::unique_ptr makes it so much simpler to deal with pointers.

Your exception probably happens because unordered_map::at requires the value to contain the key you are asking for, in order to retrieve the reference to the value it is mapping. If you use operator[] instead like in my example, the map will create an entry if the key is not found.

If you still insist on having the outer map's values to be pointers to the inner map, then you can add elements like this:

std::unordered_map<int, Foo*> &inner = *data[postCode];
inner[int(k1.Kundennr)] = new Foo(&k1);

or

data[postCode]->operator[](int(k1.Kundennr)) = new Foo(&k1);
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks! ->operator[] did exactly what I was looking for. I might be far of with that but I used the inner map as a pointer because I thougth it to be faster. I am not sure if I should use smart pointers, I am working on a programm that's older than 20 years and we have a LOT of raw pointers, I was teached not to mix those two
Your thought is wrong, if you are lucky it would be not slower
If you can't use smart pointers, then be aware that data[postCode][0] = new Foo() may leak memory if you don't check if a previous entry exists for the same key. All in all, unordered_map exists since C++11, so if you are including a modern feature into old code, you might as well do it properly.
All the Data comes from a Database postCode is (obviously) not unique. But the second iterator is a unique customerID so the possibillity if this just beeing overridden is very small to non existent. Still thanks for the advise!
@alovaros I doubt you can reliable test the difference for additional indirection, anyway std::unordered_map stpores its values in dynamically allocated memory so you do not win anything, that's for sure.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.