std::map default value

后端 未结 12 1945
旧巷少年郎
旧巷少年郎 2020-11-28 06:09

Is there a way to specify the default value std::map\'s operator[] returns when an key does not exist?

相关标签:
12条回答
  • 2020-11-28 06:56

    Maybe you can give a custom allocator who allocate with a default value you want.

    template < class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key,T> > > class map;
    
    0 讨论(0)
  • 2020-11-28 07:00

    Use std::map::insert().

    Realizing that I'm quite late to this party, but if you're interested in the behaviour of operator[] with custom defaults (that is, find the element with the given key, if it isn't present insert an element in the map with a chosen default value and return a reference to either the newly inserted value or the existing value), There is already a function available to you pre C++17: std::map::insert(). insert will not actually insert if the key already exists, but instead return an iterator to the existing value.

    Say, you wanted a map of string-to-int and inserts a default value of 42 if the key wasn't present yet:

    std::map<std::string, int> answers;
    
    int count_answers( const std::string &question)
    {
        auto  &value = answers.insert( {question, 42}).first->second;
        return value++;
    }
    
    int main() {
    
        std::cout << count_answers( "Life, the universe and everything") << '\n';
        std::cout << count_answers( "Life, the universe and everything") << '\n';
        std::cout << count_answers( "Life, the universe and everything") << '\n';
        return 0;
    }
    

    which should output 42, 43 and 44.

    If the cost of constructing the map value is high (if either copying/moving the key or the value type is expensive), this comes at a significant performance penalty, which I think would be circumvented with C++17's try_emplace.

    0 讨论(0)
  • 2020-11-28 07:02

    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;
    }
    
    0 讨论(0)
  • 2020-11-28 07:08

    One workaround is to use map::at() instead of []. If a key does not exist, at throws an exception. Even nicer, this also works for vectors, and is thus suited for generic programming where you may swap the map with a vector.

    Using a custom value for unregistered key may be dangerous since that custom value (like -1) may be processed further down in the code. With exceptions, it's easier to spot bugs.

    0 讨论(0)
  • 2020-11-28 07:12

    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

    0 讨论(0)
  • 2020-11-28 07:13

    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.
    0 讨论(0)
提交回复
热议问题