【问题标题】:Static initialization of large map大地图的静态初始化
【发布时间】:2016-12-28 01:20:07
【问题描述】:

我正在静态初始化一个大的(~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 构造函数的一部分放入堆栈,则此警告是合理的。

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

【问题讨论】:

  • 为什么不从一些文本文件中加载它们而不是对字符串进行编码,例如csv
  • stackoverflow.com/questions/10951447/load-stdmap-from-text-file 这样的东西绝对可行,还有其他选择吗?如果可能的话,我想保留地图const
  • tbh 我认为没有更好的方法。从文本文件加载字符串会产生很多好处。一方面,您不必在每次键值更改时都重新编译。此外,您可以在 Excel 中可视化您的 csv 并检查重复或错误。
  • 为了保持它为常量或隐藏它,我将创建一个“getter”函数,将其中的映射声明为static,并返回对它的引用。该函数应该加载一次。
  • 这段代码是否在命名空间范围内?

标签: c++ static-initialization


【解决方案1】:

任何合理大小的映射可能最好从文件中初始化:除了避免堆栈大小的问题外,它也往往更容易维护。另一方面,无论出于何种原因,文件都可能无法访问,因此将数据嵌入到程序中可能是有利的,尤其是当它本质上是不可变的时。请注意,结果映射的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&lt;...&gt;,因此在程序中存储数据的替代方案是具有相应元素的静态数组,然后将其用作初始化映射的底层序列。例如:

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

【讨论】:

    猜你喜欢
    • 2012-11-07
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多