стандартное значение std :: map

Можно ли указать значение по умолчанию std::map operator[] возвращает, когда ключ не существует?

65 голосов | спросил anon 25 FebruaryEurope/MoscowbThu, 25 Feb 2010 14:57:07 +0300000000pmThu, 25 Feb 2010 14:57:07 +030010 2010, 14:57:07

10 ответов


0

Нет, нет. Самое простое решение - написать собственную бесплатную функцию шаблона для этого. Что-то вроде:

#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

Цель: учет общих ассоциативных контейнеров, а также необязательных параметров компаратора и распределителя.

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;
}
ответил 25 FebruaryEurope/MoscowbThu, 25 Feb 2010 15:10:37 +0300000000pmThu, 25 Feb 2010 15:10:37 +030010 2010, 15:10:37
0

Хотя это не совсем отвечает на вопрос, я обошел проблему с таким кодом:

struct IntDefaultedToMinusOne
{
    int i = -1;
};

std::map<std::string, IntDefaultedToMinusOne > mymap;
ответил SurvivalMachine 11 AMpSat, 11 Apr 2015 11:32:59 +030032Saturday 2015, 11:32:59
0

Стандарт C ++ (23.3.1.2) определяет, что вновь добавленное значение создается по умолчанию, поэтому map само по себе не обеспечивает способ сделать это. Ваш выбор:

  • Дайте типу значения конструктор по умолчанию, который инициализирует его тем значением, которое вы хотите, или
  • Оберните карту в свой собственный класс, который предоставляет значение по умолчанию и реализует operator[] для вставки этого значения по умолчанию.
ответил Mike Seymour 25 FebruaryEurope/MoscowbThu, 25 Feb 2010 15:07:42 +0300000000pmThu, 25 Feb 2010 15:07:42 +030010 2010, 15:07:42
0

Более общая версия, поддержка C ++ 98/03 и другие контейнеры

Работает с общими ассоциативными контейнерами, единственным параметром шаблона является сам тип контейнера.

Поддерживаемые контейнеры: std::map, std::multimap, std::unordered_map, std::unordered_multimap, wxHashMap, QMap, QMultiMap, QHash, QMultiHash и т. Д.

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;
}

Использование:

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

Вот аналогичная реализация с использованием класса-оболочки, который больше похож на метод get() из dict в 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);
}

Использование:

std::map<int, std::string> t;
t[1] = "one";
string s = wrap_map(t).get(2, "unknown");
ответил jyw 16 72014vEurope/Moscow11bEurope/MoscowSun, 16 Nov 2014 18:56:45 +0300 2014, 18:56:45
0
template<typename T, T X>
struct Default {
    Default () : val(T(X)) {}
    Default (T const & val) : val(val) {}
    operator T & () { return val; }
    operator T const & () const { return val; }
    T val;
};

<...>

std::map<KeyType, Default<ValueType, DefaultValue> > mapping;
ответил Thomas Eding 8 PM00000090000000031 2012, 21:49:00
0

Нет способа указать значение по умолчанию - это всегда значение, созданное по умолчанию (конструктор с нулевым параметром).

На самом деле operator[], вероятно, делает больше, чем вы ожидаете, как если бы значение не существовало для данного ключа в карте, которую он вставит новый со значением из конструктора по умолчанию.

ответил Michael Anderson 25 FebruaryEurope/MoscowbThu, 25 Feb 2010 15:02:36 +0300000000pmThu, 25 Feb 2010 15:02:36 +030010 2010, 15:02:36
0

C ++ 17 предоставляет try_emplace, который делает именно это. Он принимает ключ и список аргументов для конструктора значений и возвращает пару: iterator и bool .: http: //en.cppreference.com/w/cpp/container/map/try_emplace

ответил Ben 10 J000000Monday17 2017, 20:22:32
0

Значение инициализируется с помощью конструктора по умолчанию, как говорят другие ответы. Однако полезно добавить, что в случае простых типов (целочисленных типов, таких как int, float, pointer или POD (планировать старые данные)), значения инициализируются нулями (или обнуляются при инициализации значений (что эффективно то же самое), в зависимости от того, какая версия C ++ используется).

В любом случае, суть в том, что карты с простыми типами автоматически инициализируют новые элементы нулями. Поэтому в некоторых случаях нет необходимости беспокоиться о явном указании начального значения по умолчанию.

std::map<int, char*> map;
typedef char *P;
char *p = map[123],
    *p1 = P(); // map uses the same construct inside, causes zero-initialization
assert(!p && !p1); // both will be 0

См. Есть ли в скобках после имени типа разница с новым? для более подробной информации по этому вопросу.

ответил the swine 7 MarpmFri, 07 Mar 2014 15:49:15 +04002014-03-07T15:49:15+04:0003 2014, 15:49:15
0

Может быть, вы можете указать пользовательский распределитель, который выделит желаемое значение по умолчанию.

template < class Key, class T, class Compare = less<Key>,
       class Allocator = allocator<pair<const Key,T> > > class map;
ответил VDVLeon 25 FebruaryEurope/MoscowbThu, 25 Feb 2010 15:06:45 +0300000000pmThu, 25 Feb 2010 15:06:45 +030010 2010, 15:06:45
0

Одним из способов решения этой проблемы является использование map::at() вместо []. Если ключ не существует, at вызывает исключение. Еще приятнее, это также работает для векторов и, следовательно, подходит для общего программирования, где вы можете поменять карту с вектором.

Использование пользовательского значения для незарегистрированного ключа может быть опасным, так как это пользовательское значение (например, -1) может быть обработано далее в коде. За исключением, легче обнаруживать ошибки.

ответил Dean 16 Jpm1000000pmWed, 16 Jan 2019 20:55:30 +030019 2019, 20:55:30

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132