EffectiveSTL4

条款19

相等和等价的区别

相等的概念是基于operator==的。如果表达式“x == y”返回true,x和y有相等的值,否则它们没有。

等价的概念是基于operator< 的。等价是基于在一个有序区间中对象值的相对位置。等价一般在每种标准关联容器(比如,set、multiset、map和multimap)的一部分——排序顺序方面有意义。两个对象x和y如果在关联容器c的排序顺序中没有哪个排在另一个之前,那么它们关于c使用的排序顺序有等价的值。

如:标准库中的find 和set 容器的成员函数find 的区别?

条款20

为指针的关联容器指定比较类型

set<string*> ssp;						// ssp = “set of string ptrs”
ssp.insert(new string("Anteater"));
ssp.insert(new string("Wombat"));
ssp.insert(new string("Lemur"));
ssp.insert(new string("Penguin"));
copy(ssp.begin(), ssp.end(),				// 把ssp中的字符串
	ostream_iterator<string>(cout, "\n"));		// 拷贝到cout(但这
							// 不能编译)

set<string*> 并不一定会按照 A , W, L, P顺序排列打印。我们必须写自己的排列算法来代替默认的。

struct StringPtrLess: public binary_function<const string*, const string*, bool>

{

      bool operator() (const string* sp1, const string* sp2) const

      {

            return *sp1 < *sp2;

      }

};

typedef set<string*, StringPtrLess> stringPtrSet;

StringPtrSet ssp;

条款21

永远让比较函数对相等的值返回false

 set<int, less_equal<int> > s;
 s.insert(10);
 s.insert(10);

结果如何:????

通常的结果是set以拥有了两个为10的值的拷贝而告终,也就是说它不再是一个set了。通过使用less_equal作为我们的比较类型,我们破坏了容器!此外,任何对相等的值返回true的比较函数都会做同样的事情。

 

struct StringPtrGreater:				// 高亮显示
public binary_function<const string*,		// 这段代码和89页的改变
const string*,					// 当心,这代码是有瑕疵的!
bool> {
	bool operator()(const string *ps1, const string *ps2) const
	{
		return !(*ps1 < *ps2);			// 只是相反了旧的测试;
	}						// 这是不对的!
};

 

multiset<int, less_equal<int> > s; // s仍然以“<=”排序

s.insert(10); // 插入10A

s.insert(10); // 插入10B

现在,s里有两个10的拷贝,因此我们期望如果我们在它上面做一个equal_range,我们将会得到一对指出包含这两个拷贝的范围的迭代器。但那是不可能的。equal_range,虽然叫这个名字,但不是指示出相等的值的范围,而是等价的值的范围。在这个例子中,s的比较函数说10A10B是不等价的,所以不可能让它们同时出现在equal_range所指示的范围内。

你明白了吗?除非你的比较函数总是为相等的值返回false,你将会打破所有的标准关联型容器,不管它们是否允许存储复本。

条款22

避免原地修改set 和multiset

因为set或multiset里的值不是const,所以试图改变它们可以编译。本条款的目的是提醒你如果你改变set或multiset里的元素, 你必须确保不改变一个键部分——影响容器有序性的元素部分。如果你做了,你会破坏容器,再使用那个容器将产生未定义的结果, 而且那是你的错误。另一方面,这个限制只应用于被包含对象的键部分。对被包含元素的所有其他部分来说,是开放的:随便改变!

 

这是同一个累人的雇员例子,这次以安全、可移植的方式写:

EmpIDSet se;					// 同前,se是一个以ID号
						// 排序的雇员set
Employee selectedID;				// 同前,selectedID是一个带有
						// 需要ID号的雇员
...
EmpIDSet::iterator i =
	se.find(selectedID);			// 第一步:找到要改变的元素
if (i!=se.end()){
	Employee e(*i);				// 第二步:拷贝这个元素
	se.erase(i++);				// 第三步:删除这个元素;
						// 自增这个迭代器以
						// 保持它有效(参见条款9)
	e.setTitle("Corporate Deity");		// 第四步:修改这个副本
	se.insert(i, e);				// 第五步:插入新值;提示它的位置
						// 和原先元素的一样
}

条款23

考虑用有序vector 代替关联容器

 需要一个提供快速查找的数据结构时,很多STL程序员立刻会想到标准关联容器:set、multiset、map和multimap。直到现在这很好,但不是永远都好。

如果查找速度真得很重要,的确也值得考虑使用非标准的散列容器(参见条款25)。如果使用了合适的散列函数,则可以认为散列容器提供了常数时间的查找。

即使你需要的就只是对数时间查找的保证,标准关联容器仍然可能不是你的最佳选择。和直觉相反,对于标准关联容器,所提供的性能也经常劣于本该比较次的vector。如果你要有效使用STL,你需要明白什么时候和怎么让一个vector可以提供比标准关联容器更快的查找。

条款24

当关乎效率时应该在map::operator[]和map-insert之间仔细选择

如果你要更新已存在的map元素,operator[]更好,但如果你要增加一个新元素,insert则有优势。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值