Key的小于操作符号重载不正确导致map占用CPU占用100%的分析

 

一、问题描述。
map的key的小于操作符重载的实现不正确,导致在删除一个元素时候,CPU占用100%。
有问题的代码如下:

using   namespace  std;
class  CUser
{
public:
    CUser(
int iID,int iKey):miID(iID),miKey(iKey){};
    
~CUser(){};
public:
    
int miID;
    
int miKey;
    
//小于操作符号重载有问题的实现
    bool operator<(const CUser &rhs) const
    
{
       
if(miID < rhs.miID)
       
{
           
return true;
       }

       
if(miKey < rhs.miKey)
       
{
           
return true;
       }
   
       
return false;
    }
;
    
//小于操作符号重载正确的实现
    /*
    bool operator<(const CUser &rhs) const
    {
       if(miID != rhs.miID)
       {
           return miID < rhs.miID;
       }
       return miKey < rhs.miKey;
    };
    
*/

}
;
typedef map
< CUser, string >  CUserMap;
typedef CUserMap::iterator CUMIterator;
int  main( int  argc,  char *  argv[])
{
 
    CUserMap cu;
    cu[CUser(
1,3)] = "1--3";//Node A
    cu[CUser(3,1)] = "3--1";//Node B
    
//该map的结构为Head(end),A,B
    cu.erase(CUser(3,1));//此处程序挂在这儿,CPU占用100%
    cout << "hello"<<endl;
    
return 0;
}

 
二、原因分析
 
1、 这是插入A、B节点后map cu的树结构
2、 STL源码分析
(1)map的删除函数
size_type erase( const  key_type &  _Keyval) //  _Keyval为B(3,1)
        {   // erase and count all that match _Keyval
       
// equal_range返回_Keyval可以插入的第一个位置和最后一个位置
//[_Where.first, _Where.second),也就是元素=_Keyval的元素区间,
//此处正确的结果应该是[B,Head(end))
//但此次结果却为[B,A),导致执行_Distance时候,出现死循环
       _Pairii _Where = equal_range(_Keyval);
       size_type _Num 
= 0;
       
//_Distance计算_Where.second到_Where.first的距离,
//是通过++计算的
       _Distance(_Where.first, _Where.second, _Num);
       erase(_Where.first, _Where.second);
       
return (_Num);
       }

 
(2)
 
template < class  _BidIt,
    
class  _Diff >  inline
       
void  _Distance2(_BidIt _First, _BidIt _Last, _Diff &  _Off,
           bidirectional_iterator_tag)
    
{   // add to _Off distance between bidirectional iterators (redundant)
    
// B++ == Head, Head ++ == Head
    for (; _First != _Last; ++_First)
       
++_Off;
    }

 (3)获取 _Where.second 的结果
_Nodeptr _Ubound( const  key_type &  _Keyval)  const
       
{   // find leftmost node greater than _Keyval
       _Nodeptr _Pnode = _Root();
       _Nodeptr _Wherenode 
= _Myhead; // end() if search fails
       
// _Keyval= B(3,1), _Pnode = A(1,3)
       while (!_Isnil(_Pnode))
           
//此处comp调用了Cuser的<,B(3,1) < A(1,3) 应该是false,但是这里却返回true
           if (this->comp(_Keyval, _Key(_Pnode)))
              
{   // _Pnode greater than _Keyval, remember it
              _Wherenode = _Pnode;
              _Pnode 
= _Left(_Pnode); // descend left subtree
              }

           
else
              _Pnode 
= _Right(_Pnode); // descend right subtree
 
       
return (_Wherenode); // return best remembered candidate
       }

   
 
3、 根本原因
在插入的时候,首先插入的是A(1,3),在插入B时候,使用的比较操作是comp(A, B),但在删除的时候,用到是comp(B,A).
comp(A, B) => A(1,3) < B(3,1) 结果为true
comp(B, A) => B(3,1) < A(1,3) 结果为true
comp(A, B)  ==  !( comp(B, A)),
即Cuser的< 不符合小于的定义
 
三、对策
1、在重载操作符时候,要使用其基本语意进行验证,看是否自相矛盾,例如在定义<时候,可以判断(A<B) != (B<A)是否为真。
2、操作符<的定义一般都是类似如下定义
          
     bool   operator < ( const  CUser  & rhs)  const
    
{
        
if(miID != rhs.miID)
        
{
            
return miID < rhs.miID;
        }

        
return miKey < rhs.miKey;
    }
;    
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值