2016-12-28 3 views
0

Я статически инициализируется большой (~ 20kb) Std :: unordered_mapстатическая инициализация большой карте

const std::unordered_map<std::string, std::string> mapStringToString{ 
{"AAF", "ELN"}, {"ACT", "POC"}, {"AEK", "THJ"}, {"AFO", "EUP"}, 
{"AHB", "HYW"}, {"AIB", "GFW"}, {"AJX", "BUX"}, {"ALD", "FKP"}, 
{"ALX", "LWB"}, {"AMY", "NQB"}, {"AOI", "GUC"}, {"ASW", "VMH"}, 
{"ATQ", "SXK"}, {"AVL", "ENB"}, {"BCJ", "NSX"}, {"BEM", "QVR"}, 
{"BGU", "WPU"}, {"BJR", "ZCS"}, {"BJT", "ZTK"}, {"BOY", "FYU"}, 
... 
{"XSJ", "FRR"}, {"XUD", "NUI"}, {"XVH", "QTI"}, {"XVJ", "TGG"}, 
{"XWK", "AZB"}, {"XYQ", "YTO"}, {"YAG", "ZQR"}, {"YAY", "UJY"}, 
{"YBN", "FEB"}, {"YCR", "EPQ"}, {"YHU", "UUD"}, {"YIG", "YMJ"}, 
{"YME", "EEZ"}, {"YNE", "EIU"}, {"YTC", "IOC"}, {"YTS", "JQM"}, 
{"YUH", "JPF"}, {"ZDY", "LFQ"}, {"ZFY", "YIH"}, {"ZMF", "BPK"}, 
{"ZPR", "TNG"}, {"ZTM", "DFJ"}, {"ZVB", "ZSV"}, {"ZXH", "IOA"}, 
{"ZZR", "RQG"}}; 

и анализ кода жалуется на использование стека:

C6262 Excessive stack usage Function uses '19920' 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> > > [249]' at line 0. Consider moving some data to heap.  <no file> 

Это предупреждение является разумным, если все данные в таблице помещаются в стек как часть конструктора unordered_map.

Есть ли лучший способ сделать эту инициализацию?

+1

Вместо того, чтобы кодировать строки, почему бы не загрузить их из какого-либо текстового файла, то есть 'csv'? –

+0

что-то вроде этого http://stackoverflow.com/questions/10951447/load-stdmap-from-text-file, безусловно, выполнимо, есть ли другие альтернативы? Я хотел бы сохранить карту 'const', если возможно – jnnnnn

+0

tbh Я не думаю, что есть лучший способ. Загрузка строк из текстового файла дает много преимуществ. во-первых, вам не нужно перекомпилировать каждый раз, когда изменяются значения ключей. Кроме того, вы можете визуализировать свой CSV в Excel и проверять наличие дубликатов или ошибок. –

ответ

2

Карта любого разумного размера, вероятно, лучше всего инициализируется из файла: кроме как избежать проблемы с размером стека, ее также легче обслуживать. С другой стороны, есть вероятность, что файл не доступен по какой-либо причине и вложение данных, особенно когда это по существу является неизменным, в программу может быть благоприятным. Обратите внимание, что нет проблемы с const ness результирующей карты: карту можно построить с помощью последовательности итератора, которая может быть прочитана из файла. Ниже приведен пример такого подхода:

#include <fstream> 
#include <iostream> 
#include <iterator> 
#include <string> 
#include <unordered_map> 

struct mystring 
    : std::string { 
}; 

std::istream& 
operator>> (std::istream& in, std::pair<mystring, std::string>& p) { 
    in >> p.first >> p.second; 
    return in; 
} 

using pair  = std::pair<mystring, std::string>; 
using iterator = std::istream_iterator<pair>; 
using map_type = std::unordered_map<std::string, std::string>; 
map_type const map(iterator(std::ifstream("map.txt") >> std::skipws), iterator()); 

int main() 
{ 
    for (auto const& p: map) { 
     std::cout << "'" << p.first << "'->'" << p.second << "'\n"; 
    } 
} 

Тип mystring необходим, чтобы иметь тип, для которого оператор ввода может быть перегружен: используя только стандартные типы библиотек, было бы необходимо, чтобы стандартная библиотека определяет оператор ввода но это не так.

Поскольку мы можем, очевидно, использовать последовательность, указанную итератором, а не std::initializer_list<...>, альтернативой хранения данных внутри программы является статический массив с соответствующими элементами, который затем используется в качестве базовой последовательности для инициализации карты. Например:

#include <algorithm> 
#include <iostream> 
#include <string> 
#include <unordered_map> 

std::pair<std::string const, std::string> values[] = { 
    { "foo1", "bar1" }, 
    { "foo2", "bar2" }, 
    { "foo3", "bar3" }, 
    { "foo4", "bar4" } 
}; 
using map_type = std::unordered_map<std::string, std::string>; 
map_type const map(std::begin(values), std::end(values)); 

int main() 
{ 
    for (auto const& p: map) { 
     std::cout << "'" << p.first << "'->'" << p.second << "'\n"; 
    } 
} 
Смежные вопросы