Инициализация статического std :: map <int, int> в C++

Как правильно инициализировать статическую карту? Нужна ли нам статическая функция, которая его инициализирует?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
476
0
473 675
11

Ответы 11

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

#include <map>
using namespace std;

map<int, char> m = {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

Используя Boost.Assign:

#include <map>
#include "boost/assign.hpp"
using namespace std;
using namespace boost::assign;

map<int, char> m = map_list_of (1, 'a') (3, 'b') (5, 'c') (7, 'd');

Каждый раз, когда я вижу что-то подобное, сделанное с помощью C++, я думаю обо всем ужасном коде шаблона, который, должно быть, стоит за этим. Хороший пример!

Greg Hewgill 26.09.2008 14:22

Он реализован «в основном» как перегруженный оператор, но если у вас когда-нибудь возникнет синтаксическая ошибка, наслаждайтесь этой строкой кода. Он втягивает 15 различных файлов .hpp для того, что займет у вас минуту или две. Код для развлечения? Используй это; в противном случае учитывайте стоимость по времени / размеру.

hazzen 26.09.2008 18:23

Boost отличный. Замечательные вещи там. Проблема в моем случае: мы не можем использовать его в качестве руководства компании. Не достаточно стандартно, недостаточно просто для среднего разработчика (не моя формулировка).

QBziZ 27.09.2008 03:54

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

Steve Guidi 13.11.2009 21:09

@QBziZ: Если ваша компания отказывается от использования Boost на том основании, что он не является «достаточно стандартным», мне интересно, какая библиотека C++ бы будет «достаточно стандартной». Boost - это стандартный компаньон то для кодировщика C++.

DevSolar 05.01.2012 17:04

@DevSolar Я хотел бы использовать Boost больше, но его синергия с C++ 11 ужасна, и есть некоторые довольно ... любопытный дизайнерские решения (Iostreams требует, чтобы устройства можно было копировать, но делает потоки некопируемыми ... о, и также неподвижный - по крайней мере, в той реализации, которую я использую, может быть, они это исправили?).

Cubic 08.05.2013 23:16

Моя проблема с Boost (здесь и где-либо еще) заключается в том, что вы часто можете обойтись без него (в данном случае с C++ 11 или до C++ 11 с функцией). Boost добавляет значительные накладные расходы на время компиляции, имеет множество файлов для хранения в вашем репозитории (и вам приходится копировать / zip / extract, если вы создаете архив). Вот почему я стараюсь не использовать его. Я знаю, что вы можете выбрать, какие файлы включать / не включать, но обычно вам не нужно беспокоиться о перекрестных зависимостях Boost с самим собой, поэтому вы просто копируете все вокруг.

bobobobo 01.06.2013 04:43

Моя проблема с Boost заключается в том, что у него часто есть несколько новых зависимостей библиотеки, что обычно означает БОЛЬШЕ пакетов, которые необходимо установить для правильной работы. Нам уже нужен libstdC++. Например, для библиотеки Boost ASIO требуется как минимум 2 новые библиотеки (возможно, больше), которые необходимо установить. C++ 11/14 значительно упрощает отказ от Boost.

Rahly 31.05.2016 23:42

@nobar очевидно, дублирующиеся ключи игнорируются, включается только первый экземпляр. Скорее всего, у меня просто нет нужных параметров компилятора для генерации предупреждений об этом.

Eusebius 20.12.2018 12:57

Почему это не удается скомпилировать на vs2017 со стандартным значением C++ 17

att 31.01.2020 13:27

Я бы обернул карту внутри статического объекта и поместил код инициализации карты в конструктор этого объекта, чтобы вы были уверены, что карта создается до выполнения кода инициализации.

Я с тобой в этом. Это также немного быстрее :)

QBziZ 27.09.2008 03:52

Чуть быстрее, чем что? Глобальная статика с инициализатором? Нет, это не так (вспомните про RVO).

Pavel Minaev 13.11.2009 22:30

Хороший ответ. Буду рад, если увижу реальный пример кода

Sungguk Lim 22.07.2014 11:58

Лучший способ - использовать функцию:

#include <map>

using namespace std;

map<int,int> create_map()
{
  map<int,int> m;
  m[1] = 2;
  m[3] = 4;
  m[5] = 6;
  return m;
}

map<int,int> m = create_map();

Хорошо, мне пришлось просто исправить ошибку сборки в MSVS'12, и это действительно помогло; быстрее, чем здесь настраивать буст.

Bartek Banachewicz 03.04.2013 12:05

Почему это «лучший»? Почему, например, это лучше, чем ответ @Dreamer?

user207421 07.05.2013 03:40

Я думаю, что это «лучший», потому что он действительно прост и не зависит от других существующих структур (таких как Boost :: Assign или его повторная реализация). И по сравнению с ответом @Dreamer, я избегаю создания всей структуры только для инициализации карты ...

PierreBdR 10.05.2013 18:54

Есть ли для этой идиомы имя? В какое «время» работает эта функция create_map? Он работает до main, что такое имя для этой среды выполнения?

bobobobo 01.06.2013 19:56
Обратите внимание, здесь есть опасность. extern variables will not have their correct values in this "before main run-time constructor" если компилятор видел только объявление extern, но еще не столкнулся с фактическим определением переменной.
bobobobo 01.06.2013 20:04

Нет, опасность состоит в том, что ничего не сказано, в каком порядке должны быть инициализированы статические переменные (по крайней мере, между единицами компиляции). Но это не проблема, связанная с этим вопросом. Это общая проблема со статическими переменными.

PierreBdR 04.06.2013 13:06

Как долго это проживет? Как распределяется его память? Немного смущен, поскольку я всегда использовал способ @eduffy.

Juto 16.02.2014 15:32

Мне нравится этот ответ, потому что он прост и удобен для компилятора. Даже в C++ 11 map <int, int> m = {{1,1}, {2,2}}; не будет работать, если ваш компилятор еще не поддерживает его.

Pittfall 11.07.2014 22:39

без повышения И без C++ 11 => +1. Обратите внимание, что функция может использоваться для инициализации const map<int,int> m = create_map() (и, следовательно, для инициализации константных членов класса в списке инициализации: struct MyClass {const map<int, int> m; MyClass(); }; MyClass::MyClass() : m(create_map())

ribamar 13.03.2015 13:00

Для меня это выглядит ужасно, но он работает в C++ 98, и это то, что я искал.

Nobody 30.11.2016 20:09

Сделать что-то похожее на буст - несложная задача. Вот класс всего с тремя функциями, включая конструктор, для воспроизведения того, что сделал boost (почти).

template <typename T, typename U>
class create_map
{
private:
    std::map<T, U> m_map;
public:
    create_map(const T& key, const U& val)
    {
        m_map[key] = val;
    }

    create_map<T, U>& operator()(const T& key, const U& val)
    {
        m_map[key] = val;
        return *this;
    }

    operator std::map<T, U>()
    {
        return m_map;
    }
};

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

std::map mymap = create_map<int, int >(1,2)(3,4)(5,6);

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

Если, скажем, вам нужно вставить элементы в существующий std :: map ... вот вам еще один класс.

template <typename MapType>
class map_add_values {
private:
    MapType mMap;
public:
    typedef typename MapType::key_type KeyType;
    typedef typename MapType::mapped_type MappedType;

    map_add_values(const KeyType& key, const MappedType& val)
    {
        mMap[key] = val;
    }

    map_add_values& operator()(const KeyType& key, const MappedType& val) {
        mMap[key] = val;
        return *this;
    }

    void to (MapType& map) {
        map.insert(mMap.begin(), mMap.end());
    }
};

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

typedef std::map<int, int> Int2IntMap;
Int2IntMap testMap;
map_add_values<Int2IntMap>(1,2)(3,4)(5,6).to(testMap);

Посмотрите его в действии с GCC 4.7.2 здесь: http://ideone.com/3uYJiH

############### ВСЕ НИЖЕ ЭТО УСТАРЕЛО #################

РЕДАКТИРОВАТЬ: приведенный ниже класс map_add_values, который был оригинальным решением, которое я предложил, потерпит неудачу, когда дело доходит до GCC 4.5+. Пожалуйста, посмотрите на приведенный выше код, чтобы узнать, как добавить значения добавлять к существующей карте.


template<typename T, typename U>
class map_add_values
{
private:
    std::map<T,U>& m_map;
public:
    map_add_values(std::map<T, U>& _map):m_map(_map){}
    map_add_values& operator()(const T& _key, const U& _val)
    {
        m_map[key] = val;
        return *this;
    }
};

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

std::map<int, int> my_map;
// Later somewhere along the code
map_add_values<int,int>(my_map)(1,2)(3,4)(5,6);

ПРИМЕЧАНИЕ. Ранее я использовал operator [] для добавления фактических значений. Это невозможно, как прокомментировал dalle.

#################### КОНЕЦ УСТАРЕВШЕГО СЕКЦИИ ########################################

Я использую ваш первый образец как <int, string> для привязки номеров ошибок (из перечисления) к сообщениям - он работает как шарм - спасибо.

slashmais 22.09.2010 14:57

operator[] принимает только один аргумент.

dalle 25.07.2011 14:35

@dalle: Хороший улов! По какой-то причине я думал, что перегруженные операторы [] могут принимать больше.

Vite Falcon 26.07.2011 14:55

Это фантастический ответ. Жаль, что ОП не выбрал ни одного. Вы заслуживаете мега-реквизита.

Thomas Thorogood 26.09.2012 22:26

map_add_values ​​не работает в gcc, который жалуется: error: conflicting declaration ‘map_add_values<int, int> my_map’error: ‘my_map’ has a previous declaration as ‘std::map<int, int> my_map’

Martin Wang 20.05.2013 09:25

@martinwang Какая версия gcc? Читая ошибку компилятора, кажется, что вы сделали что-то вроде map_add_values my_map.... Вы используете его, как показано в моем примере использования?

Vite Falcon 20.05.2013 17:52

GCC4.5.1. Твой пример я пробовал. GCC просто сбивает с толку зависание анонимного объекта. class A{}; A a(); в порядке. class A{}; A(); приводит к ошибке компиляции.

Martin Wang 21.05.2013 05:46

@MartinWang, понятно. Это тот случай, когда GCC считает, что утверждение map_add_values<int,int>(my_map)(1,2)(3,4); похоже на map_add_values<int, int> my_map(1,2)(3,4);. Я ищу элегантное решение.

Vite Falcon 21.05.2013 07:04

@MartinWang, у меня есть более новое решение. Кажется, он работает с GCC 4.7.2, и вы можете видеть, что он компилируется на ideone. Я переместил свое исходное (сломанное) решение в конец для исторического отслеживания.

Vite Falcon 21.05.2013 07:18

Ну, ваш пример используется в main (). Подвешивание анонимного объекта по-прежнему запрещено в глобальном пространстве имен. Нравится class A {public: A(int){} void to(){}}; A(1).to();

Martin Wang 21.05.2013 09:09

Мое решение использует уникальное пространство имен, в котором анонимный объект присваивается переменной. Для простоты весь код, определенный в макросе, используется как MAP_ADD(mymap,int,int, (1,2)(3,4));.

Martin Wang 21.05.2013 09:15

@MartinWang - Можно ли передать указатель на структуру вместо значения int? map <int, указатель на класс> вместо map <int, int> в этом примере? Благодарность

ejuser 16.07.2014 10:35

@ejuser вы можете передать тип указателя, в чем ваш смысл?

Martin Wang 16.07.2014 11:49

@MartinWang - На самом деле есть 2 вопроса, связанных с этим (при необходимости я могу открыть другой поток) <br/> Вопрос 1: (отдельная проблема) - Невозможно использовать строку <br/> std :: map mymap = create_map <int, интервал> (1,2) (3,4) (5,6); <br/> Вопрос 2: Будут ли утечки памяти, если не очистить карту? Нужно ли нам добавлять какие-либо конкретные явные команды для очистки карты (бесплатно (карта))? <br/> Вопрос 3. Есть ли способ расширить это как unique_pointer до map <int, <unique_ptr> class> <br/>

ejuser 16.07.2014 17:59

@ejuser 1. покажите свой код и проблемы. 2. Нет необходимости в delete/free, если не используется new/malloc. 3. Аргументы шаблона - это типы, а не конкретный указатель, я вас не понимаю.

Martin Wang 16.07.2014 20:19

Позвольте нам продолжить обсуждение в чате.

ejuser 16.07.2014 21:35

Привет, хорошее решение, но я думаю, что map_add_values ​​было бы лучше таким образом: template <typename MapType> class map_adder {private: MapType & mMap; общедоступные: typedef typename MapType :: key_type KeyType; typedef typename MapType :: mapped_type MappedType; map_adder (MapType & Map): mMap (Карта) {} map_adder & operator () (const KeyType & key, const MappedType & val) {mMap [key] = val; return * this; }}; шаблон <typename Maptype> map_adder <Maptype> map_add_values ​​(Maptype & data2change) {return map_adder <Maptype> (data2change); } -> map_add_values ​​(mymap) (3,3);

jamk 28.10.2014 12:34

Это похоже на PierreBdR, без копирования карты.

#include <map>

using namespace std;

bool create_map(map<int,int> &m)
{
  m[1] = 2;
  m[3] = 4;
  m[5] = 6;
  return true;
}

static map<int,int> m;
static bool _dummy = create_map (m);

Вероятно, его все равно бы не скопировали.

GManNickG 13.11.2009 22:21

но в этом случае карта не может быть статической константой, не так ли?

xmoex 24.11.2013 14:58

Вот еще один способ использования двухэлементного конструктора данных. Для его инициализации не требуется никаких функций. Нет стороннего кода (Boost), нет статических функций или объектов, нет трюков, просто C++:

#include <map>
#include <string>

typedef std::map<std::string, int> MyMap;

const MyMap::value_type rawData[] = {
   MyMap::value_type("hello", 42),
   MyMap::value_type("world", 88),
};
const int numElems = sizeof rawData / sizeof rawData[0];
MyMap myMap(rawData, rawData + numElems);

Поскольку я написал этот ответ, C++ 11 отсутствует. Теперь вы можете напрямую инициализировать контейнеры STL, используя новую функцию списка инициализаторов:

const MyMap myMap = { {"hello", 42}, {"world", 88} };

У вас есть несколько очень хороших ответов, но для меня это похоже на случай, когда все, что вы знаете, - это молоток ...

Самый простой ответ на вопрос, почему нет стандартного способа инициализировать статическую карту, заключается в том, что нет веской причины когда-либо использовать статическую карту ...

Карта - это структура, предназначенная для быстрого поиска неизвестного набора элементов. Если вы знаете элементы заранее, просто используйте C-массив. Введите значения в отсортированном порядке или выполните сортировку по ним, если вы не можете этого сделать. Затем вы можете получить производительность log (n), используя stl :: functions для циклических записей, lower_bound / upper_bound. Когда я тестировал это ранее, они обычно работают как минимум в 4 раза быстрее, чем карта.

Преимущества многочисленны ... - более высокая производительность (* 4, я измерял на многих типах процессоров, всегда около 4) - более простая отладка. Просто с линейной компоновкой проще увидеть, что происходит. - Тривиальные реализации операций копирования, если в этом возникнет необходимость. - Он не выделяет память во время выполнения, поэтому никогда не вызовет исключение. - Это стандартный интерфейс, поэтому его очень легко использовать, используя библиотеки DLL, языки и т. д.

Я мог бы продолжить, но если вы хотите большего, почему бы не заглянуть в многочисленные блоги Страуструпа по этой теме.

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

MatthiasB 21.07.2014 16:59

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

KarlU 28.10.2014 19:48

map также является полезной формой для представления частичной функции (функции в математическом смысле; но также в некотором роде в смысле программирования). Массив этого не делает. Вы не можете, скажем, искать данные из массива, используя строку.

einpoklum 20.07.2015 22:21

Ваш ответ не является попыткой ответить на действительный вопрос, а вместо этого размышляет об ограничениях языка, предлагает решения различных проблем, следовательно, голосует против. Реальный сценарий - отображение кодов ошибок библиотеки (непрерывных или нет) в текстовые строки. С массивом время поиска составляет O (n), что можно улучшить статическим сопоставлением с O (log (n)).

Tosha 22.01.2016 14:41

Если действительно «нет веской причины когда-либо использовать статическую карту ...», то очень странно, что синтаксис (списки инициализаторов), упрощающий их использование, был добавлен в C++ 11.

ellisbben 01.07.2016 18:09

@Tosha: Я думаю, что ответ относится к вашему сценарию и описывает, как его можно искать в O (log (n)) без использования карты. См. Где я могу найти «полезный» алгоритм двоичного поиска C++?.

Brent Bradburn 17.08.2016 07:40

Просто хотел поделиться чистой работой С ++ 98:

#include <map>

std::map<std::string, std::string> aka;

struct akaInit
{
    akaInit()
    {
        aka[ "George" ] = "John";
        aka[ "Joe" ] = "Al";
        aka[ "Phil" ] = "Sue";
        aka[ "Smitty" ] = "Yando";
    }
} AkaInit;

это не работает для объекта без конструктора по умолчанию, метод вставки должен быть предпочтительным IMHO

Alessandro Teruzzi 04.10.2016 12:47

Можешь попробовать:

std::map <int, int> mymap = 
{
        std::pair <int, int> (1, 1),
        std::pair <int, int> (2, 2),
        std::pair <int, int> (2, 2)
};

Вы не можете использовать списки инициализаторов с неагрегатными типами до C++ 11, и в этом случае вы также можете использовать более короткий синтаксис {1, 2} вместо std::pair<int, int>(1, 2).

Ferruccio 21.02.2018 15:28

Например:

const std::map<LogLevel, const char*> g_log_levels_dsc =
{
    { LogLevel::Disabled, "[---]" },
    { LogLevel::Info,     "[inf]" },
    { LogLevel::Warning,  "[wrn]" },
    { LogLevel::Error,    "[err]" },
    { LogLevel::Debug,    "[dbg]" }
};

Если карта является членом данных класса, вы можете инициализировать ее непосредственно в заголовке следующим образом (начиная с C++ 17):

// Example

template<>
class StringConverter<CacheMode> final
{
public:
    static auto convert(CacheMode mode) -> const std::string&
    {
        // validate...
        return s_modes.at(mode);
    }

private:
    static inline const std::map<CacheMode, std::string> s_modes =
        {
            { CacheMode::All, "All" },
            { CacheMode::Selective, "Selective" },
            { CacheMode::None, "None" }
            // etc
        };
}; 

Если вы застряли на C++ 98 и не хотите использовать ускорение, вот решение, которое я использую, когда мне нужно инициализировать статическую карту:

typedef std::pair< int, char > elemPair_t;
elemPair_t elemPairs[] = 
{
    elemPair_t( 1, 'a'), 
    elemPair_t( 3, 'b' ), 
    elemPair_t( 5, 'c' ), 
    elemPair_t( 7, 'd' )
};

const std::map< int, char > myMap( &elemPairs[ 0 ], &elemPairs[ sizeof( elemPairs ) / sizeof( elemPairs[ 0 ] ) ] );

Другие вопросы по теме