大地图静态初始化
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
构造函数的一部分放入堆栈,则此警告是合理的。
有没有更好的方法来进行这个初始化?
任何合理大小的地图可能最好从文件中初始化:除了避免堆栈大小的问题外,它也往往更容易维护。另一方面,无论出于何种原因,文件都可能无法访问,将数据(尤其是当它本质上不可变时)嵌入到程序中可能是有利的。请注意,结果映射的 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";
}
}
我正在静态初始化一个大的 (~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
构造函数的一部分放入堆栈,则此警告是合理的。
有没有更好的方法来进行这个初始化?
任何合理大小的地图可能最好从文件中初始化:除了避免堆栈大小的问题外,它也往往更容易维护。另一方面,无论出于何种原因,文件都可能无法访问,将数据(尤其是当它本质上不可变时)嵌入到程序中可能是有利的。请注意,结果映射的 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";
}
}