现在的位置: 首页 > 综合 > 正文

EffectiveSTL2

2013年12月01日 ⁄ 综合 ⁄ 共 2414字 ⁄ 字号 评论关闭

条款7

class SpecialString: public string {....}

这种行为很危险,因为string像所有的标准STL容器,缺少虚席够函数,从而没有虚析构函数的类共有继承是一个大的c++禁忌。

条款8

typedef typename iterator_traits<RandomAccessIterator>::value_type ElementType;

涉及在模板中到模板类或普通类中自定义的类型时,需要用typename 来修饰,否则c++ 编译器把value_type 当做静态数据。

条款9

关联容器 AssocContainer<int> c;

for (AssocContainer<int>::iterator i = c.begin();

       i != c.end();

       i++)

{

    if (badVallue(*i))

             c.erase(i);

}

清晰但漏洞百出,删除c 中的badvalue 返回真的每个元素,当c.erase(i)后, i 迭代器失效,但却要执行 ++i,这是个坏消息。解决方案

for (AssocContainer<int>::iterator i = c.begin();

       i != c.end(); )

{

    if (badVallue(*i))

             c.erase(i++);

    else

        ++i;

}

 

为vector,string,deque这样的容器调用erase不仅使所有指向被删呀unsede迭代器失效,也是被删元素之后的所有迭代器失效。 我们这里写的 i++,++i 都不能导致迭代器有效。(deque 可能特殊)

for (SeqContainer<int>::iterator i = c.begin(); 
	i != c.end();){
	if (badValue(*i)){
		logFile << "Erasing " << *i << '\n'; 
		i = c.erase(i);			// 通过把erase的返回值
	}					// 赋给i来保持i有效
	else
		++i;
}

你可以像vector/string/deque一样或像关联容器一样对待list;两种方法都可以为list工作。

两种情况:一般vector,string,deque 在erase时使当前迭代器和其后的迭代器都失效,而关联容器仅仅使当前迭代器失效。

条款10

  • 把你的分配器做成一个模板,带有模板参数T,代表你要分配内存的对象类型。
  • 提供pointer和reference的typedef,但是总是让pointer是T*,reference是T&。
  • 决不要给你的分配器每对象状态。通常,分配器不能有非静态的数据成员。
  • 记得应该传给分配器的allocate成员函数需要分配的对象个数而不是字节数。也应该记得这些函数返回T*指针(通过pointer typedef),即使还没有T对象被构造。
  • 一定要提供标准容器依赖的内嵌rebind模板。

记得要看:Austern的文章《What Are Allocators Good For?》

条款11

关于共享内存的对象

mallocShared、freeShared

placement new 的用法

new(void* pT)T(initValue);

条款12

STL容器线程安全:

多个读取者是安全的。

对不同容器的多个写入者是安全的。多个线程可以同时写不容的容器

 

STL容器不是线程安全的,要实现线程安全的STL库很难,只能交给用户去负担。

vector<int> v;
vector<int>::iterator first5(find(v.begin(), v.end(), 5));	// 行1
if (first5 != v.end()){					// 行2
	*first5 = 0;					// 行3
}

会出现的情况:

1 行2对first5 和 v.end 的检测将是无意义的

2 另一线程插在行1 和行2 之间,使 first5 失效,造成 vector重新分配它的内在内存。

3 行3对 *first5 的赋值是不安全的,应为另一个线程可能在行2 和行  3 之间执行,使 first5 失效,已经删除指向它的元素。

要让上面的代码成为线程安全的,v必须从行1到行3保持锁定。

 

关于互斥:

手工版:

vector<int> v;
...
getMutexFor(v);
vector<int>::iterator first5(find(v.begin(), v.end(), 5));
if (first5 != v.end()) {						// 这里现在安全了
	*first5 = 0;						// 这里也是
}
releaseMutexFor(v);

工业级版:

template<typename Container>				// 获取和释放容器的互斥量
class Lock {						// 的类的模板核心;
public:							// 忽略了很多细节
	Lock(const Containers container)
			: c(container)
	{
		getMutexFor(c);				// 在构造函数获取互斥量
	}

	~Lock()
	{
		releaseMutexFor(c);			// 在析构函数里释放它
	}

private:
	const Container& c;
};
vector<int> v;
...
{								// 建立新块;
	Lock<vector<int> > lock(v);					// 获取互斥量
	vector<int>::iterator first5(find(v.begin(), v.end(), 5));
	if (first5 != v.end()) {
		*first5 = 0;
	}
}								// 关闭块,自动
								// 释放互斥量

关于两者的区别:

这种基于Lock的方法在有异常的情况下是稳健的。C++保证如果抛出了异常,局部对象就会被销毁,所以即使当我们正在使用Lock对象时有异常抛出,Lock也将释放它的互斥量。如果我们依赖手工调用getMutexFor和releaseMutexFor,那么在调用getMutexFor之后releaseMutexFor之前如果有异常抛出,我们将不会释放互斥量。

抱歉!评论已关闭.