[C++]关于map的Key值

我们知道,对于map的键类型,唯一的约束是必须支持<操作符,至于是否支持其他的关系或相等运算,则不做要求

如果map的Key为内置类型,则通常已支持<操作,比如map<int>,int类型已经支持<


如果是自定义类型呢?则必须重载<!


class MyStruct
{
public:
	int x;
	int y;
	int z;

	MyStruct(int ix=0,int iy=0,int iz=0)
	{
		x = ix;
		y = iy;
		z = iz;
	}
};
map<MyStruct,string> mm;

mm.insert(make_pair(MyStruct(1,1,1),"1") );

如果没有重载<,编译的时候会报错:

d:\program files\microsoft visual studio 9.0\vc\include\functional(143) : error C2784: “bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)”: 无法从“const MyStruct”为“const std::_Tree<_Traits> &”推导 模板 参数
1>        d:\program files\microsoft visual studio 9.0\vc\include\xtree(1466) : 参见“std::operator <”的声明

于是这里重载下<
friend bool operator< (const MyStruct &ms1,const MyStruct &ms)
	{
		return ms1.x < ms.x && ms1.y < ms.y && ms1.z < ms.z;
	}


下面原意想插入3条记录:
mm.insert(make_pair(MyStruct(1,1,1),"1") );
mm.insert(make_pair(MyStruct(1,2,1),"2"));
mm.insert(make_pair(MyStruct(1,1,0),"3"));

经过调试代码,我们发现,实际只插入成功了第1条:



这是为什么呢?

------------------------------------华丽丽的分割线-------------------------------------------


这还得从map的机制说起,比如上面有调用3次map的insert接口

第一次:map为空,插入成功

第二次/第三次:查找key是否存在,如果已存在,则插入失败


所以看来问题应该出在查找Key上面

从Key类型的定义来看,我们只重载了<,那在做insert操作时,如何判断Key是否存在?

前面我们已经说过,Key只定义了<号的约束,是否重载==,并不关注,所以这里不能通过重载==判断Key是否存在


其实,通过<也能判断一个值是否相等

比如a=1,b=2,当!(a<b) && !(b<a)时,a和b相等,这里!(1<2)为fasle,所以1!=2

if a=1,b=1 --> !(1<1) && !(1<1)  为真,则可认为两个数相等


其实从这里可以看出一个重载map Key类型<号的一个基本原则,即当a<b为真时,b<a则必定为假,反正亦然,这样才能保证正确的通过<判断出==


再看下我们之前重载的<

return ms1.x < ms.x && ms1.y < ms.y && ms1.z < ms.z;

1、已存在(1,1,1),再计算插入(1,2,1)

上面我们说了,基本原则为:a<b为和b<a的值要求不一致,但是这里明显不符合:

第一次调用时首先判断1<1,为假,operator<会直接返回fasle

第二次调用时,按照我们的原则,如果返回true,则重载<是正确的,但很不幸,还是比较1<1,依旧为false

显然,这里重载<是错误的


那如何才能重载出正确的<呢?

这里给一个正确的例子:

friend bool operator< (const MyStruct &ms1,const MyStruct &ms)
	{
		if (ms1.x != ms.x)
		{
			return ms1.x < ms.x;
		}

		if (ms1.y != ms.y)
		{
			return ms1.y < ms.y;
		}

		if (ms1.z != ms.z)
		{
			return ms1.z < ms.z;
		}

		return false;
	}

这里当判断a<b时,会返回false

b<a时,同样也会返回false


执行结果:



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值