【Effective STL】条款6-12学习笔记

条款6:警惕C++最令人恼怒的解析

参数为double变量
int f(double d); 
 
   
int f(double (d));	// 同上;d左右的括号被忽略
 
   
int f(double);		// 同上;参数名被省略
参数为函数指针
int g(double (*pf)());	// g带有一个指向函数的指针作为参数
int g(double pf());	// 同上;pf其实是一个指针
int g(double ());		// 同上;参数名省略

以下写法是错误的:
ifstream dataFile("ints.dat");
list data(istream_iterator(dataFile),	// 警告!这完成的并不
		istream_iterator());		// 是像你想象的那样

如果出现这个函数:
list data(istream_iterator(dataFile), istream_iterator()); 
第一个参数类型istream_iterator
第二个参数类型是返回istream_iterator的函数指针
解决方法:
ifstream dataFile("ints.dat");
istream_iterator dataBegin(dataFile);
istream_iterator dataEnd;
list data(dataBegin, dataEnd);

条款7:当使用new得指针的容器时,记得在销毁容器前delete那些指针

容器很智能,在容器销毁时(例如:函数中声明的局部变量容器)会自动删除容器内所有数据,但不包括指针。如果传入的是new进去的指针,会产生大量的内存泄露,因为指针的“析构函数”是无操作!它肯定不会调用delete。
解决方法:
1.显式调用delete
2.
template
struct DeleteObject :				// 条款40描述了为什么
	public unary_function {	// 这里有这个继承
	void operator()(const T* ptr) const
	{
		delete ptr;
	}
};

现在你可以这么做:

void doSomething()
{
	...	// 同上
	for_each(vwp.begin(), vwp.end(), DeleteObject);
}
这话中方法存在不少问题,比如有人恶意从string继承,string和所有的标准STL容器一样缺少"虚"析构函数。
如果这样:
struct DeleteObject {				// 删除这里的
						// 模板化和基类
	template 			// 模板化加在这里
	void operator()(const T* ptr) const 
	{ 
		delete ptr; 
	} 
}
就可以解决上面的那个问题,但是如果之间异常也会出现内存泄露,所以!
void doSomething()
{
	typedef boost::shared_ ptr SPW;	//SPW = "shared_ptr
						// to Widget"
	vector vwp;
	for (int i = 0; i < SOME_MAGIC_NUMBER; ++i)
		vwp.push_back(SPW(new Widget));	// 从一个Widget建立SPW,
						// 然后进行一次push_back
		...			// 使用vwp
}					// 这里没有Widget泄漏,甚至
					// 在上面代码中抛出异常
看来看去看不懂。
对了,要避免suto_ptr的容器来形成可以自动删除的指针。

条款8:永不建立auto_ptr的容器

使用auto_pt的容器页就是COAPs在C++标准里面是不被认可的。
如果这么做:
auto_ptr pw1(new Widget);		// pw1指向一个Widget 
auto_ptr pw2(pw1);			// pw2指向pw1的Widget; 
					// pw1被设为NULL。(Widget的
					// 所有权从pw1转移到pw2。)
pw1 = pw2;				// pw1现在再次指向Widget;
					// pw2被设为NULL
如果容器进行sort排序的话就会出现一些指针变成NULL

条款9:在删除选项中仔细选择、

想把容器中所有1963对象都删除
连续内存容器(vector、deque、string)使用erase-remove
c.erase(remove(c.begin(), c.end(), 1963),		// 当c是vector、string
		c.end());				// 或deque时,
						// erase-remove惯用法
						// 是去除特定值的元素
						// 的最佳方法
list使用
c.remove(1963);		// 当c是list时,
			// remove成员函数是去除
			// 特定值的元素的最佳方法
对于关联容器
c.erase(1963);		// 当c是标准关联容器时
			// erase成员函数是去除
			// 特定值的元素的最佳方法
消除下面判断式:
bool badValue(int x);	// 返回x是否是“bad”
序列容器:
c.erase(remove_if(c.begin(), c.end(), badValue),	// 当c是vector、string
			c.end());			// 或deque时这是去掉
						// badValue返回真
						// 的对象的最佳方法
c.remove_if(badValue);				// 当c是list时这是去掉
						// badValue返回真
						// 的对象的最佳方法
标准关联容器:
AssocContainer c;				// c现在是一种
...						// 标准关联容器
AssocContainer goodValues;			// 用于容纳不删除
						// 的值的临时容器
remove_copy_if(c.begin(), c.end(),			// 从c拷贝不删除
		inserter(goodValues,		// 的值到
			goodValues.end()),		// goodValues
			badValue);
c.swap(goodValues);				// 交换c和goodValues
						// 的内容

条款10:注意分配器的协定和约束

条款11:理解自定义分配器的正确用法

条款12:对STL容器线程安全性的期待现实一些

关于分配器,后边会有单独一篇来介绍,我对分配器的理解还在粗浅阶段,《Effective STL》里面的条款10-11无法理解。
对于多线程以及STL容器线程安全性同样感到困惑,暂时放下。期待后面解决
—— by Gustav 2013-7-18 9:39:14















你可能感兴趣的:(STL,STL)