Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map default value

Tags:

c++

stdmap

People also ask

What is the default value of map in C++?

A map is a container which is used to store a key-value pair. By default, In Primitive datatypes such as int, char, bool, float in C/C++ are undefined if variables are not initialized, But a Map is initially empty when it is declared.

How do you initialize a map to 0?

What exactly do you want to initialize to zero? map's default constructor creates empty map. You may increase map's size only by inserting elements (like m["str1"]=0 or m. insert(std::map<std::string,int>::value_type("str2",0)) ).

Is map ordered by default?

By default, a Map in C++ is sorted in increasing order based on its key.


No, there isn't. The simplest solution is to write your own free template function to do this. Something like:

#include <string>
#include <map>
using namespace std;

template <typename K, typename V>
V GetWithDef(const  std::map <K,V> & m, const K & key, const V & defval ) {
   typename std::map<K,V>::const_iterator it = m.find( key );
   if ( it == m.end() ) {
      return defval;
   }
   else {
      return it->second;
   }
}

int main() {
   map <string,int> x;
   ...
   int i = GetWithDef( x, string("foo"), 42 );
}

C++11 Update

Purpose: Account for generic associative containers, as well as optional comparator and allocator parameters.

template <template<class,class,class...> class C, typename K, typename V, typename... Args>
V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval)
{
    typename C<K,V,Args...>::const_iterator it = m.find( key );
    if (it == m.end())
        return defval;
    return it->second;
}

While this does not exactly answer the question, I have circumvented the problem with code like this:

struct IntDefaultedToMinusOne
{
    int i = -1;
};

std::map<std::string, IntDefaultedToMinusOne > mymap;

C++17 provides try_emplace which does exactly this. It takes a key and an argument list for the value constructor and returns a pair: an iterator and a bool.: http://en.cppreference.com/w/cpp/container/map/try_emplace


The C++ standard (23.3.1.2) specifies that the newly inserted value is default constructed, so map itself doesn't provide a way of doing it. Your choices are:

  • Give the value type a default constructor that initialises it to the value you want, or
  • Wrap the map in your own class that provides a default value and implements operator[] to insert that default.

More General Version, Support C++98/03 and More Containers

Works with generic associative containers, the only template parameter is the container type itself.

Supported containers: std::map, std::multimap, std::unordered_map, std::unordered_multimap, wxHashMap, QMap, QMultiMap, QHash, QMultiHash, etc.

template<typename MAP>
const typename MAP::mapped_type& get_with_default(const MAP& m, 
                                             const typename MAP::key_type& key, 
                                             const typename MAP::mapped_type& defval)
{
    typename MAP::const_iterator it = m.find(key);
    if (it == m.end())
        return defval;

    return it->second;
}

Usage:

std::map<int, std::string> t;
t[1] = "one";
string s = get_with_default(t, 2, "unknown");

Here is a similar implementation by using a wrapper class, which is more similar to the method get() of dict type in Python: https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hpp

template<typename MAP>
struct map_wrapper
{
    typedef typename MAP::key_type K;
    typedef typename MAP::mapped_type V;
    typedef typename MAP::const_iterator CIT;

    map_wrapper(const MAP& m) :m_map(m) {}

    const V& get(const K& key, const V& default_val) const
    {
        CIT it = m_map.find(key);
        if (it == m_map.end())
            return default_val;

        return it->second;
    }
private:
    const MAP& m_map;
};

template<typename MAP>
map_wrapper<MAP> wrap_map(const MAP& m)
{
    return map_wrapper<MAP>(m);
}

Usage:

std::map<int, std::string> t;
t[1] = "one";
string s = wrap_map(t).get(2, "unknown");

There is no way to specify the default value - it is always value constructed by the default (zero parameter constructor).

In fact operator[] probably does more than you expect as if a value does not exist for the given key in the map it will insert a new one with the value from the default constructor.