IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    迭代中释放hash_map key的内存

    dutor发表于 2012-03-17 18:01:51
    love 0

      这么一段程序,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    typedef __gnu_cxx::hash_map<object *, object *, object_equal_to, object_hasher> object_hash_map_t;
    object_hash_map_t hash_map;
    hash_map.insert(make_pair(new object, new object));
    object_hash_map_t::iterator it = hash_map.begin();
    while (it != hash_map.end()) {
        delete it->first;
        delete it->second;
        ++it;
    }

      该程序core而不止。因为STL的代码很多都被内联了,调试起来不方便,于是看了下sgi的STL实现,发现了问题。首先,STL的hash_map是由hashtable实现的,hash_map只是对hashtable的一个封装。hashtable也只是很普通的实现,使用单链表解决冲突。下面是hashtable中对迭代器的operator++操作的实现,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    struct _Hashtable_node {
        _Hashtable_node *_M_next;
        _Val _M_val; //~ pair<Key, Value>
    };
    typedef _Hashtable_node _Node; //~ omitting the template arguments
    struct _Hashtable_iterator {
        _Node *_M_cur;
        _Hashtable *_M_ht;
        _Hashtable_iterator& operator++() {
             const _Node* __old = _M_cur; //! preserve the old node
             _M_cur = _M_cur->_M_next;
             if (!_M_cur) {
                 size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); //! get bucket number with hash key 
                 while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
                 _M_cur = _M_ht->_M_buckets[__bucket];
             }
             return *this;
         }
    };

      了然了,iterator的operator++需要根据key计算出迭代器当前所在的bucket,然后在此bucket及后续bucket中顺序遍历以寻找下一个元素。所以在开头的示例代码中,由于在迭代过程中释放了key的内存,当迭代器“递增”计算当前bucket number时当然就core掉了。
      hash_map在STL中已经被标记为deprecated,已经过时了,若要使用hash_map,建议使用具有相同接口和特性的unordered_map。
      另外,使用hash_map时,一定要注意模板参数equal_to和hash_func,前者用来判断key是否相等,后者用来计算key的hash值,稍有不慎就会出现莫名其妙的错误,例如著名的hash_map的遍历死循环问题。



沪ICP备19023445号-2号
友情链接