skip to Main Content

I’ve read conflicting ideas about what to do with large unordered maps, whether to allocate them on the heap vs the stack depending on its size being known/not at compile time. So hopefully someone can clear this up once and for all, because even as I’ve tried to move my large map to the heap, visual studio still warns me about it needing to be put on the heap.

defs.cpp

unordered_map<string, string>* Keywords = new unordered_map<string, string>({...});

defs.h

extern unordered_map<string, string>* Keywords;

The map has a size of 55k and is defined in the code and will never change as the app runs.
I repeat, the app never edits this map, it never adds to it, it never removes from it. the pairs are set in the defs.cpp file as described, before the code is compiled, the list is there. That’s why I put […] as placeholder to avoid pasting 1000+ lines of text.
I repeat, the example is exactly as described, this is the minimum reproductible example, there are no other parts required, this is 100% of the code you need.
It just needs to exist and be accessible to many parts of the app. From what I understand, the new keyword should already be allocating on the heap?

Any help is much appreciated, thank you.

edit: for reference here’s the warning shown by Visual Studio

C6262: Function uses '55360' bytes of stack: exceeds /analyze:stacksize '16384'..
This allocation was for a compiler-generated temporary for 'struct std::pair<class std::basic_string<char,struct std::char_traits<char>, class std::allocator<char>>const,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>>[865] at line XXX. 
Consider moving some data to heap.

3

Answers


  1. std::unordered_map<K,V> must allocate the storage for its elements dynamically. To see why, you can for example consider that sizeof(std::unordered_map<K,V>) is a compile time constant. The elements are not stored directly within the map object but elsewhere.

    The same is true for most other containers (std::array is an exception). Hence, you almost never need to dynamically allocate the container.

    (And just assumed you did, then you would not use new and raw pointers.)

    Login or Signup to reply.
  2. I will risk a glimpse into the crystal ball. When you write

    unordered_map<string, string>* Keywords =
        new unordered_map<string, string>({...});
    

    Then you actually have an enormous number of values between the brackets in {...}. These values are allocated on the stack no matter how you allocate the unordered_map. Without knowing what you actually have there, it is next to impossible to suggest suitable workarounds.

    Login or Signup to reply.
  3. The compiler warning is not about the hash map, it’s about the initial data for the map, which you put inside your ({...}). That code allocates an object of type std::initializer_list<something>, that object contains a long array, and that array is on the stack.

    Consider moving that initialization data somewhere else, here’s an example.

    #include <string>
    #include <unordered_map>
    
    namespace
    {
        // Initial data for the map
        using namespace std::string_literals;
        static std::pair<std::string, std::string> s_mapInitialData[] =
        {
            {"key1"s, "value1"s},
            {"key2"s, "value2"s},
        };
    
        // Create a hash map from the above data.
        // Calling this function destroys the data in s_mapInitialData array
        // The strings are being moved from there into the new map
        static std::unordered_map<std::string, std::string> createTheMap()
        {
            std::unordered_map<std::string, std::string> res;
            res.reserve( std::size( s_mapInitialData ) );
            for( auto& p : s_mapInitialData )
                res.emplace( std::move( p ) );
            return res;
        }
    }
    
    // Call this function to get the const reference to the hash map
    // This function is thread-safe, BTW.
    const std::unordered_map<std::string, std::string>& getTheMap()
    {
        static const std::unordered_map<std::string, std::string> map = createTheMap();
        return map;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search