/****************************************************************/
/* 学习是合作和分享式的!
/* Author:Atlas Email:wdzxl198@163.com
/* 转载请注明本文出处:
* http://blog.csdn.net/wdzxl198/article/details/9112123
/****************************************************************/
上期内容回顾:
2.1-2.2 RAII规则(引入) 2.3 smart pointer 2.4 auto_ptr类
2.5 资源传递
资源传递(Resource Transfer)主要是讲述在不同的作用域间安全的传递资源。这一问题在当你处理容器的时候会变得十分明显。你可以动态的创建一串对象,将它们存放至一个容器中,然后将它们取出,并且在最终安排它们。为了能够让这安全的工作——没有泄露——对象需要改变其所有者。
这个问题的一个非常显而易见的解决方法是使用Smart Pointer,无论是在加入容器前还是还找到它们以后。这是他如何运作的,你加入Release方法到Smart Pointer中:
1: template <class T>
2: T * SmartPointer<T>::Release ()
3: {
4: T * pTmp = _p;
5: _p = 0;
6: return pTmp;
7: }
注意在Release调用以后,Smart Pointer就不再是对象的所有者了——它内部的指针指向空。现在,调用了Release都必须是一个负责的人并且迅速隐藏返回的指针到新的所有者对象中。在我们的例子中,容器调用了Release,比如这个Stack的例子:
1: void Stack::Push (SmartPointer <Item> & item) throw (char *)
2: {
3: if (_top == maxStack)
4: throw "Stack overflow";
5: _arr [_top++] = item.Release ();
6: };
同样的,你也可以再你的代码中用加强Release的可靠性。
这部分内容可以参考学习《C++内存管理学习笔记(3)》中的auto_ptr智能指针,auto_ptr对象通过赋值、复制和reset操作改变对象的所有者。
2.6 共享所有权
为每一个程序中的资源都找出或者指定一个所有者,对于共享所有权来说是最好的的选择方式。
共享的责任分配给被共享的对象和它的客户(client)。一个共享资源必须为它的所有者保持一个引用计数。另一方面,所有者再释放资源的时候必须通报共享对象。最后一个释放资源的需要在最后负责free的工作。
例子:最简单的共享的实现是共享对象继承引用计数的类RefCounted:
1: class RefCounted
2: {
3: public:
4: RefCounted () : _count (1) {}
5: int GetRefCount () const { return _count; }
6: void IncRefCount () { _count++; }
7: int DecRefCount () { return --_count; }
8: private:
9: int _count;
10: };
按照资源管理,一个引用计数是一种资源。如果你遵守它,你需要释放它。当你意识到这一事实的时候,剩下的就变得简单了。简单的遵循规则--再构造函数中获得引用计数,在析构函数中释放。
在上一个学习笔记(3)中提到过,智能指针有两种方式,分别为设置拥有权的转移和使用引用计数的方式。针对这个两个解决方案,出现了两种风格的智能指针,STL中的auto_ptr属于拥有权转移指针,boost中的shared_ptr属于引用计数型(boost里面的智能指针有6个,scoped_ptr、scoped_array、shared_array、intrusive_ptr、weak_ptr)。
小问:STL和boost? 1.STL 标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年,直到标准的出台才正式定型,但是在标准库的实现上却很令人欣慰得看到多种实现,并且已被实践证明为有工业级别强度的佳作。 STL的最主要的两个特点:数据结构和算法的分离,非面向对象本质。访问对象是通过象指针一样的迭代器实现的;容器是象链表,矢量之类的数据结构,并按模板方式提供;算法是函数模板,用于操作容器中的数据。由于STL以模板为基础,所以能用于任何数据类型和结构. (1) STL是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用。例如,由于STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组。 (2) STL它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。你在STL中找不到任何明显的类继承关系。这好像是一种倒退,但这正好是使得STL的组件具有广泛通用性的底层特征。另外,由于STL是基于模板,内联函数的使用使得生成的代码短小高效。 2.boost Boost库是一个经过千锤百炼、可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起,在C++社区中影响甚大,其成员已近2000人。 Boost库为我们带来了最新、最酷、最实用的技术,是不折不扣的“准”标准库。 Boost中比较有名气的有这么几个库: Regex:正则表达式库; Spirit LL parser framework,用C++代码直接表达EBNF Graph:图组件和算法; Lambda:在调用的地方定义短小匿名的函数对象,很实用的functional功能 concept check:检查泛型编程中的concept Mpl:用模板实现的元编程框架 Thread:可移植的C++多线程库 Python:把C++类和函数映射到Python之中 Pool:内存池管理 smart_ptr Boost总体来说是实用价值很高,质量很高的库。并且由于其对跨平台的强调,对标准C++的强调,是编写平台无关,现代C++的开发者必备的工具。但是Boost中也有很多是实验性质的东西,在实际的开发中实用需要谨慎。并且很多Boost中的库功能堪称对语言功能的扩展,其构造用尽精巧的手法,不要贸然的花费时间研读。Boost另外一面,比如Graph这样的库则是具有工业强度,结构良好,非常值得研读的精品代码,并且也可以放心的在产品代码中多多利用。 区别: boost是一个准标准库,相当于STL的延续和扩充,它的设计理念和STL比较接近,都是利用泛型让复用达到最大化。不过对比STL,boost更加实用。 STL集中在算法部分,而boost包含了不少工具类,可以完成比较具体的工作。 |
接下来对share_ptr进行讲解,share_ptr是可以共享所有权的智能指针。
2.7 share_ptr
(1)boost中的智能指针
Boost提供了下面几种智能指针(Smart Pointers to boost your code):
将原文部分放上来,防止笔者翻译水平有限,影响大家阅读,请对照内容:
share_ptr<T> | 使用一个引用计数器来判断此指针是不是需要被释放。是boost中最常用的智能指针了。 |
scope_ptr<T> | 当这个指针的作用域消失之后自动释放,性能与内置的指针差不多 |
intrusive_ptr<T> | 也维护一个引用计数器,比shared_ptr有更好的性能。但是要求T自己提供这个引用计数机制。 |
weak_ptr<T> | 弱指针,要和shared_ptr 结合使用避免循环引用 |
share_array<T> | 和shared_ptr相似,但是访问的是数组 |
scope_array<T> | 和scoped_ptr相似,但是访问的是数组 |
(2)share_ptr引入
首先,我们通过例子来了解这个智能指针,
1: void Sample_Shared()
2: {
3: // (A) create a new CSample instance with one reference
4: boost::shared_ptr<CSample> mySample(new CSample);
5: printf("The Sample now has %i references\n", mySample.use_count()); // should be 1
6:
7: // (B) assign a second pointer to it:
8: boost::shared_ptr<CSample> mySample2 = mySample; // should be 2 refs by now
9: printf("The Sample now has %i references\n", mySample.use_count());
10: