Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default value of static std::unordered_map

I would like to know the default value of variables inside a struct of static static std::unordered_map<std::string, struct>.

Here's my example code:

#include <iostream>
#include <string>
#include <unordered_map>

int main()
{
    enum MyStateType
    {
        MY_STATE_NEW,
        MY_STATE_RUN,
        MY_STATE_FREE
    };
    struct Foo
    {
        int num;
        MyStateType state;
    };
    static std::unordered_map<std::string, Foo> map;

    std::cout << map["Apple"].num << '\n';
    std::cout << map["Apple"].state << '\n';
}

The output result:

0
0
Program ended with exit code: 0

Is it safe to think that variables inside Foo are always initialized to 0 in the beginning?

like image 652
Zack Lee Avatar asked Aug 03 '18 07:08

Zack Lee


People also ask

What is the default value in unordered_map?

As you might expect, an unordered_map returns the default value for the value type if the key is not found in the map (count[5] will return 0 in this case).

Is unordered_map initialized with 0?

The value object is value-initialized, not zero-initialized.

What is default size of unordered_map?

std::unordered_map::unordered_map Constructs an empty unordered_map object, containing no elements and with a size of zero.

How do I set a default value on a map?

To initialize the map with a random default value below is the approach: Approach: Declare a structure(say struct node) with a default value. Initialize Map with key mapped to struct node.


1 Answers

Yes, it is actually safe to assume that the values inside Foo are always initialized to zero because of the behaviour of operator[]

When the default allocator is used, this results in the key being copy/move constructed from key and the mapped value being value-initialized.

You do not provide a constructor which means that each field in Foo will be value initialized individually which for primitive types means zero initialization.

but

The problem you are actually facing here is that a field called "Apple" does not exist in your map. Unfortunately the semantics of operator[] are such that if the value does not exist, it will be created on the fly. You probably didn't even want to access a non-existent field in the map and you are asking whether it is always initialized to zero so that you can use this fact to check whether the element was there. For this purpose however, you should either use the find() or at() member function.

  • find() will return an iterator pointing to the end of the map if the element does not exist. That means you could guards the element access using

    if (auto apple = map.find("Apple"); apple != map.end()) {
        std::cout << apple->second.num << '\n';
        std::cout << apple->second.state << '\n';
    }
    

    (with the C++17 if statement initializer)

  • at() will throw an exception if the element is not found.

    std::cout << map.at("Apple").num << '\n';
    std::cout << map.at("Apple").state << '\n';
    

    This will crash your program with a std::out_of_range exception. You might feel temped to catch this exception to check whether the element existed. Don't do this. It is very bad practice to use exceptions for control flow. On top of that exception are dead slow when they are being thrown.

like image 163
Henri Menke Avatar answered Sep 20 '22 16:09

Henri Menke