大地图静态初始化

Static initialization of large map

我正在静态初始化一个大的 (~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>   

如果 table 中的所有数据都作为 unordered_map 构造函数的一部分放入堆栈,则此警告是合理的。

有没有更好的方法来进行这个初始化?

任何合理大小的地图可能最好从文件中初始化:除了避免堆栈大小的问题外,它也往往更容易维护。另一方面,无论出于何种原因,文件都可能无法访问,将数据(尤其是当它本质上不可变时)嵌入到程序中可能是有利的。请注意,结果映射的 constness 没有问题:映射可以由一系列可以从文件中读取的迭代器构建。这是此方法的示例:

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