说明unordered_map是一个关联容器,包含键值唯一的键值对。搜索、插入和元素移除具有平均常数时间复杂度。元素在内部不按任何特定顺序排序,而是组织到桶中。一个元素被放入哪个桶完全取决于它的键的哈希值。这允许快速访问单个元素,因为一旦计算出哈希值,它就会准确地引用元素被放入的桶。问题原系统基于GCC4.8.5,使用C++11标准开发,内部基于unordered_map存储数据。新系统首先升级到GCC7.3.0,依然使用C++11标准开发。新旧系统基于一个持久化文件恢复数据,按相同顺序插入unordered_map,遍历unordered_map组包对外发送。通过比较新旧系统对外发送的报文内容的一致性,验证新旧系统的正确性。但是经过验证的现象是新旧系统之间发送数据包的顺序不一致。原因分析不同GCC版本hash策略不同,插入时rehash时机不同(__prime_list不同)。初始桶大小不同。GCC4.8.5默认值为10,之后的版本取消了默认值。根本原因:initialbucketsize应该和每次插入的bucketsize一致。解决方案将GCC7.3.0中的hash策略换成GCC4.8.5(标准库生成弱符号,用stub.cpp替换为强符号)//stub.cpp#include#include#includenamespacestd{namespace__detail{externconstunsignedlong__prime_list[]=//256+1或256+48+1{2ul,3ul,5ul,7ul,11ul,13ul,17ul,19ul,23ul,29ul,31ul,37ul,41ul,43ul,47ul,53ul,59ul,61ul,67ul,71ul,73ul,79ul,83ul,89ul,97ul,103ul,109ul,113ul,1277ul,1139ul,149ul,157ul,167ul,19ul,1939ul,211ul,227ul,241ul,257ul,277ul,293ul,313ul,337ul,359ul,383ul,409ul,439ul,467ul,503ul,541ul,577ul,619ul,661ul,709ul,761ul,823ul,887ul,953ul,1031ul,1109ul,1193ul,1289ul,1381ul,1493ul,1613ul,1741ul,1879ul,2029ul,2179ul,2357ul,2549ul,2753ul,2971ul,3209ul,3469ul,3739ul,4027ul,47083ul,47083ul5503ul,5953ul,6427ul,6949ul,7517ul,8123ul,8783ul,9497ul,10273ul,11113ul,12011ul,12983ul,14033ul,15173ul,16411ul,17749ul,19183ul,20753ul,22447ul,24281ul,26267ul,28411ul,30727ul,33223ul,35933ul,38873ul,42043ul,45481ul,49201ul,53201ul,57557ul,62233ul,67307ul,72817ul,78779ul,85229ul,92203ul,99733ul,107897ul,116731ul,126271ul,136607ul,147793ul,159871ul,172933ul,187091ul,202409ul,218971ul,236897ul,256279ul,277261ul,299951ul,324503ul,351061ul,379787ul,410857ul,444487ul,480881ul,520241ul,562841ul,608903ul,658753ul,712697ul,771049ul,834181ul,902483ul,976369ul,1056323ul,1142821ul,1236397ul,1337629ul,1447153ul,1565659ul,1693859ul,1832561ul,1982627ul,2144977ul,2320627ul,2510653ul,2716249ul,2938679ul,3179303ul,3439651ul,3721303ul,4026031ul,4355707ul,4712381ul,5098259ul,5515729ul,5967347ul,6456007ul,6984629ul,7556579ul,8175383ul,8844859ul,9569143ul,10352717ul,11200489ul,12117689ul,13109983ul,14183539ul,15345007ul,16601593ul,17961079ul,19431899ul,21023161ul,22744717ul,24607243ul,26622317ul,28802401ul,31160981ul,33712729ul,36473443ul,39460231ul,42691603ul,46187573ul,49969847ul,54061849ul,58488943ul,63278561ul,68460391ul,74066549ul,80131819ul,86693767ul,93793069ul,101473717ul,109783337ul,118773397ul,128499677ul,139022417ul,150406843ul,162723577ul,176048909ul,190465427ul,206062531ul,222936881ul,241193053ul,260944219ul,282312799ul,305431229ul,330442829ul,357502601ul,386778277ul,418451333ul,452718089ul,489790921ul,529899637ul,573292817ul,620239453ul,671030513ul,725980837ul,785430967ul,849749479ul,919334987ul,994618837ul,1076067617ul,1164186217ul,1259520799ul,1362662261ul,1474249943ul,1594975441ul,1725587117ul,1866894511ul,2019773507ul,2185171673ul,2364114217ul,2557710269ul,2767159799ul,2993761039ul,3238918481ul,3504151727ul,3791104843ul,4101556399ul,4294967291ul,//Sentinel,所以我们不必测试表的结果,lower_6,rest_4,if__SIZEOF_LONG__!=84294967291ul#else6442450933ul,8589934583ul,12884901857ul,17179869143ul,25769803693ul,34359738337ul,51539607367ul,68719476731ul,103079215087ul,137438953447ul,206158430123ul,274877906899ul,412316860387ul,549755813881ul,824633720731ul,1099511627689ul,1649267441579ul,2199023255531ul,3298534883309ul,4398046511093ul,6597069766607ul,8796093022151ul,13194139533241ul,17592186044399ul,26388279066581ul,35184372088777ul,52776558133177ul,70368744177643ul,105553116266399ul,140737488355213ul,211106232532861ul,281474976710597ul,562949953421231ul,1125899906842597ul,2251799813685119ul,4503599627370449ul,9007199254740881ul,18014398509481951ul,36028797018963913ul,72057594037927931ul,144115188075855859ul,288230376151711717ul,576460752303423433ul,1152921504606846883ul,2305843009213693951ul,4611686018427387847ul,9223372036854775783ul,18446744073709551557ul,18446744073709551557ul#endif};///重新哈希策略的默认值。桶大小(通常)是///保持负载因子足够小的最小素数。struct_Prime_rehash_policy{_Prime_rehash_policy(float__z=1.0);floatmax_load_factor()constnoexcept;//返回一个不小于n的桶大小。std::size_t_M_next_bkt(std::size_t__n)常量;//返回适合n个元素的桶计数std::size_t_M_bkt_for_elements(std::size_t__n)const;//__n_bkt是当前桶数,__n_elt是当前元素数,//__n_ins是要插入的元素数。我们需要//增加桶数吗?如果是,则返回make_pair(true,n),其中n//是新的桶计数。如果不是,则返回make_pair(false,0)。std::pair_M_need_rehash(std::size_t__n_bkt,std::size_t__n_elt,std::size_t__n_ins)const;typedefstd::size_t_State;_State_M_state()常量;void_M_reset(_State__state);枚举{_S_n_primes=sizeof(unsignedlong)!=8?256:256+48};静态常量std::size_t_S_growth_factor=2;浮动_M_max_load_factor;可变std::size_t_M_next_resize;};_Prime_rehash_policy::_Prime_rehash_policy(float__z):_M_max_load_factor(__z),_M_next_resize(0){}float_Prime_rehash_policy::max_load_factor()constnoexcept{返回_M_max_load_factor;}std::size_t_Prime_rehash_policy::_M_bkt_for_elements(std::size_t__n)const{return__builtin_ceil(__n/(longdouble)_M_max_load_factor);}_Prime_rehash_policy::_State_Prime_rehash_policy::_M_state()const{返回_M_next_resize;}void_Prime_rehash_policy::_M_reset(_State__state){_M_next_resize=__state;}//返回一个不小于n的素数。std::size_t_Prime_rehash_policy::_M_next_bkt(std::size_t__n)const{//优化涉及__prime_list的第一个元素的查找。//(有助于加速,例如,构造函数)staticconstunsignedchar__fast_bkt[12]={2,2,2,3,5,5,7,7,11,11,11,11};如果(__n<=11){_M_next_resize=__builtin_ceil(__fast_bkt[__n]*(longdouble)_M_max_load_factor);返回__fast_bkt[__n];}constunsignedlong*__next_bkt=std::lower_bound(__prime_list+5,__prime_list+_S_n_primes,__n);_M_next_resize=__builtin_ceil(*__next_bkt*(longdouble)_M_max_load_factor);返回*__next_bkt;}//找到满足alphap>__n_elt+__n_ins的最小素数p。//如果p>__n_bkt,返回make_pair(true,p);否则返回rn//make_pair(false,0).原则上这与//_M_bkt_for_elements没有太大区别。//唯一棘手的部分是我们将元素计数缓存在//我们需要重新散列的位置,因此我们不必为每次插入都进行浮点//乘法。std::pair_Prime_rehash_policy::_M_need_rehash(std::size_t__n_bkt,std::size_t__n_elt,std::size_t__n_ins)const{如果(__n_elt+__n_ins>=_M_next_resize){longdouble__min_bkts=(__n_elt+__n_ins)/(longdouble)_M_max_load_factor;如果(__min_bkts>=__n_bkt)返回std::make_pair(true,_M_next_bkt(std::max(__builtin_floor(__min_bkts)+1,__n_bkt*_S_growth_factor)));_M_next_resize=__builtin_floor(__n_bkt*(longdouble)_M_max_load_factor);返回std::make_pair(false,0);}否则返回std::make_pair(false,0);}}//命名空间__detail}//命名空间std将GCC7.3.0的初始桶大小设置为10#include#include#includeintmain(){//创建三个字符串的unordered_map(映射到字符串)std::unordered_map你;你.储备(10);std::cout<<"load_factor:"<(u.size()+1);std::cout<<"will_rehash:"<