0

I want a struct that has an unordered_map as a member.
I also don't want to type out the type all the time, so I typedef it.

typedef std::unordered_map<std::string, int> HM;
struct A {
    HM myHm;
}

A *myA = new A();
HM hashmap = new HM(); // empty hashmap
hashmap["1"] = 1;
myA->myHm = hashmap;

Of course this isn't correct.

I see examples of people doing std::unordered_map<std::string, int> HM;
And then immediately HM["1"] = 1;

First of all, I'm used to Java where std::unordered_map<std::string, int> HM; is just a type and if I want to add stuff to it, I need to instantiate it with ().

It seems that in C++, it's instantiated the moment I write std::unordered_map<std::string, int> HM;. Can anyone offer some insight into this?

Second, what is the correct way of doing what I want?

6
  • That code compiles and does what you would expect (well, if you put the code inside a function it would). Commented Nov 27, 2015 at 4:32
  • A mA; HM hashmap; are sufficient and preferred in C++ to create fully-fledged objects. No new means no memory leaks (usually). Also you are creating a hash map as a local variable and then copying it into the hash map in your struct. Why not just use that one directly? Commented Nov 27, 2015 at 4:32
  • @JamesPicone I get conversion from ‘HM*’ to non-scalar type ‘HM’ requested when I assign HM() to HM hashmap. Commented Nov 27, 2015 at 4:43
  • 1
    Are you sure this is the same code? Commented Nov 27, 2015 at 4:45
  • 1
    I have that code in a compiler right now; it definitely behaves. Are you sure you haven't written new HM(), or some equivalent? Commented Nov 27, 2015 at 4:45

2 Answers 2

4

In C++ you would normally not write this:

HM hashmap = HM();

That's because what you're doing there is to create an anonymous temporary with HM() (the default constructor), then assign it to another one called hashmap. Instead, you can simply do this:

HM hashmap;

That will equally default-construct a hash map, and avoids any potential unnecessary assignment or double-construction.

Another issue with your existing code is that you use new and store the result in a "raw" pointer, but never call delete on it. Instead, you can skip using new altogether, and avoid redundancy, like this:

A myA; // contains HM
myA.myHm["1"] = 1;

This does everything you need in the minimal number of steps.

Sign up to request clarification or add additional context in comments.

Comments

0

A way of thinking about things that might help is to think of all variables in C++ as being 'value types', in C# lingo (I don't know what the appropriate Java term is).

This Java is perfectly legal:

int foo;
foo = 2;
foo *= 17

because 'foo' is just a value, it lives entirely on the stack and doesn't need to be allocated.

In Java, when you declare a variable of a complex type (say, a HashMap) it doesn't live on the stack, and it has to be allocated. In C++, when you declare a variable of a complex type, that's exactly what you get, and it lives on the stack. If you want a reference type, you have to explicitly ask for it.

The term to look for is 'auto variables'. Variables declared inside a function are 'auto variables', they have their constructors called when execution gets to their declaration, and they have their destructors called when their scope is left. Here's a link to the appropriate Wikipedia page.

It's a really useful behavior, and it lies behind a common C++ idiom called RAII.

If you want to call a non-default constructor of the type, you can just add parentheses:

SomeType foo(p1, p2);

That calls SomeType::SomeType(p1, p2) to construct foo.

Comments

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.