Effective STL:19 - 25 关联容器

本文探讨了C++中关联容器的使用技巧,包括理解相等与等价的区别、为包含指针的容器指定比较类型、正确实现比较函数、安全修改set及multiset中的元素等内容。

19.理解相等(equality)和等价(equivalence)的区别。

相等的概念是以operator==为基础的,而等价的概念则是以operator<为基础的。


相等基于operator==,所以应该记住,x和y有相等的值并不意味的它们所有的数据成员都相等。


而等价关系是以“”在已排序的区间中对象值的相对顺序“为基础。如果按照关联容器c的排列顺序,每个都不在另一个的前面。假如x和y有等价的值,那么

!c.key_comp(x,y) && !c.key_comp(y,x) 为true。


20.为包含指针的关联容器指定比较类型。

如果想让指针在集合中按照某种需要的排序方式排序,那么不能使用默认的排序比较函数,必须自己编写比较子类。仔细分析下面的代码,结果都一样,但是个人还是比较喜欢StringPtrLess2。

#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <iterator>

using namespace std;

class StringPriLess
{
public:
	bool operator()(const string *ps1,const string *ps2) const
	{
		return *ps1 < *ps2;
	}
};

class StringPtrLess2
{
public:
	template<typename T>
	bool operator()(const T* ps1, const T *ps2)
	{
		return *ps1 < *ps2;
	}
};

class StringPtrLess3
{
public:
	template<typename T>
	bool operator()(T pt1,T pt2) const
	{
		return *pt1 < *pt2;
	}
};

void print(const string *ps)
{
	cout << *ps << endl;
}

class Dereference
{
public:
	template<typename T>
	const T& operator()(const T* ptr) const
	{
		return *ptr;
	}
};

int main()
{
	typedef set<string*,StringPtrLess3> stringPtrSet;
	stringPtrSet ssp;

	ssp.insert(new string("Anteater"));
	ssp.insert(new string("Wombat"));
	ssp.insert(new string("Lemur"));
	ssp.insert(new string("Penguin"));


//	for_each(ssp.begin(),ssp.end(),print);

	transform(ssp.begin(),ssp.end(),ostream_iterator<string>(cout,"\n"),Dereference());

	return 0;
}


21.总是让比较函数在等值的情况下返回false。

记结论。比较函数的返回值表明的是按照该函数定义的排顺序,一个值是否在另一个之前,相等的值从来不会有前后顺序关系,所以,相等的值,比较函数总是应该返回false。


如:set<int,less_equal<int> >s就是一个典型的在等值的情况下返回true的例子。如果插入同样的值,比如说10,按照条款19,两者等价是下面式子

!c.key_comp(x,y) && !c.key_comp(y,x) 为true。

而!(10 <= 10) && !(10 <= 10)这个式子结果为false,证明不等价,两个10会插在一起(挨个),从技术上讲,这样的容器会导致不确定的行为。


而a < b是等价于b > a而不是b >= a。所以说set<int,less<int> >和set<int,greater<int> >都对,set<int,less_equal<int> >和set<int,greater_equal<int> >是错误的。


结论就是,比较函数在等值的情况下返回false,不然会破坏所有的标准关联容器。


22.切勿直接修改set或者multiset中的键。

map和multimap的键不能更改,而set和multiset可以修改与集合排序无关的部分。


而C++标准委员会认为map/multimap的键应该是const 的,而set/multiset的值应该不是。所以如果要改变set或者multiset中的元素,一定不要修改键的部分


下面提供一种安全的修改set或者multiset的方法:

EmpIDSet se;

Employee selectedID;

……

EmpIDSet::iterator i = se.find(selectedID);

if(i != se.end())

{

   Employee e(*i);

   e.setTitle("Corporate Deity");

   se.erase(i++);

   se.insert(i,e);

}

上面的方法大致分五步:

1.找到想要修改的元素。

2.对这份元素做一个拷贝。

3.修改该拷贝。

4.把该元素从容器中删除。

5.把新的值插到容器中。


23.考虑用排序的vector代替关联容器。

关联容器不是用来排序的。


24.当效率至关重要的时候,请在map::operator[]与map::insert之间谨慎做出选择。

map的[]实际上是首先调用默认构造函数,然后立刻赋予新值。

结论就是,如果要更新一个已有的元素,优先考虑operator[],但是如果要添加一个新的元素,最好选择insert。


25.熟悉非标准的哈希容器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值