今天在看effective modernc++的时候注意到了一个细节,在用c++11新标准遍历map时的参数的类型的key要为const,否则访问的是一个局部对象,这个我一直都没有注意到,现在复习一下:
查阅http://www.cplusplus.com/reference/map/map/?kw=map
注意到map声明为
template < class Key, // map::key_type class T, // map::mapped_type class Compare = less<Key>, // map::key_compare class Alloc = allocator<pair<const Key,T> > // map::allocator_type > class map;
unordermap也是一样。key有const修饰。
测试以下代码
int main() { map<std::string, int> m; m["1"] = 1; for (const std::pair<std::string, int>& p : m) { cout << "addr in local:" << &p << " addr in object:" << &(*m.begin())<<endl; } for (const auto& p : m) { cout << "addr in local:" << &p << " addr in object:" << &(*m.begin())<<endl; } system("pause"); return 0; }
结果为:
addr in local:00000031A98FF468 addr in object:000001F6028059B0
addr in local:000001F6028059B0 addr in object:000001F6028059B0
可以看到第一次以非const访问时的地址的不同。其原因是因为遍历放回的类型为std::pair<const std::string,int>,而循环中的声明的类型为std::pair<std::string,int>,编译器能够为上述类型进行隐式的转化:先拷贝一个局部变量,然后for中的p就引用到这个临时变量上。
review一下的底层原理:
map底层是一个平衡二叉树,红黑树,插入与删除时间复杂度为O(lgn)。
unorderedmap则是一个链表,使用开放定址法的链式hash策略。插入与删除最好是常量,最坏是O(n)。rehash时最好是O(n),最坏是O(n^2)