2016-12-28 1 views
0

J'Initialisation statiquement un grand (~ 20kb) std :: unordered_mapinitialisation statique de grande carte

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

et l'analyse de code se plaint de l'utilisation de la pile:

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> 

Cet avertissement est raisonnable si toutes les données de la table sont mises dans la pile dans le cadre du constructeur unordered_map.

Y a-t-il un meilleur moyen de faire cette initialisation?

+1

Au lieu de coder les chaînes, pourquoi ne pas les charger à partir d'un fichier texte, c'est-à-dire 'csv'? –

+0

quelque chose comme ça http://stackoverflow.com/questions/10951447/load-stdmap-from-text-file est définitivement faisable, existe-t-il d'autres alternatives? Je voudrais garder la carte 'const' si possible – jnnnnn

+0

tbh Je ne pense pas qu'il existe un meilleur moyen. Le chargement des chaînes à partir d'un fichier texte présente de nombreux avantages. pour un, vous n'avez pas à recompiler chaque fois que les valeurs des clés changent. En outre, vous pouvez visualiser votre csv dans Excel et vérifier les doublons ou les erreurs. –

Répondre

2

Une carte de toute taille raisonnable est probablement mieux initialisée à partir d'un fichier: en plus d'éviter le problème avec la taille de la pile, elle tend également à être plus facile à maintenir. D'autre part, il y a une chance que le fichier ne soit pas accessible pour quelque raison que ce soit et l'intégration des données, surtout lorsqu'elles sont essentiellement immuables, dans le programme peut être favorable. Notez qu'il n'y a pas de problème avec const de la carte résultante: la carte peut être construite par une séquence d'itérateur pouvant lire à partir d'un fichier. Voici un exemple de cette approche:

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

Le type mystring est nécessaire d'avoir un type pour lequel l'opérateur d'entrée peut être surchargé: en utilisant uniquement les types de bibliothèque standard, il serait nécessaire que la bibliothèque standard définit un opérateur d'entrée mais il ne le fait pas. Puisque nous pouvons évidemment utiliser une séquence spécifiée par l'itérateur plutôt qu'une std::initializer_list<...>, une alternative stockant les données dans le programme est un tableau statique avec les éléments correspondants qui est ensuite utilisé comme séquence sous-jacente pour initialiser la carte. Par exemple:

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