智能指针
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在你的代码中使用Boost智能指针
Smart Pointers to boost your code(By peterchen)
翻译 masterlee
Download source files - 45.3kb
正文
智能指针能够使C++的开发简单化,主要是它能够像其它限制性语言(如C#、VB)自动管理内存的释放,而且能够做更多的事情。
1、什么是智能指针
智能指针是一种像指针的C++对象,但它能够在对象不使用的时候自己销毁掉。
我们知道在C++中的对象不再使用是很难定义的,因此C++中的资源管理是很复杂的。各种智能指针能够操作不同的情况。当然,智能指针能够在任务结束的时候删除对象,除了在程序之外。
许多库都提供了智能指针的操作,但都有自己的优点和缺点。Boost库是一个高质量的开源的C++模板库,很多人都考虑将其加入下一个C++标准库的版本中。
下面让我们看一个简单的例子:
2、首先介绍:boost::scoped_ptr
scoped_ptr 是 Boost 提供的一个简单的智能指针,它能够保证在离开作用域后对象被释放。
例子说明:本例子使用了一个帮助我们理解的类: CSample, 在类的构造函数、赋值函数、析构函数中都加入了打印调试语句。因此在程序执行的每一步都会打印调试信息。在例子的目录里已经包含了程序中需要的Boost库的部分内容,不需要下载其它内容(查看Boost的安装指南)。
使用普通普通指针的时候,我们必须记住在函数退出的时候要释放在这个函数内创建的对象。当我们使用例外的时候处理指针是特别烦人的事情(容易忘记销毁它)。使用scoped_ptr 指针就能够在函数结束的时候自动销毁它,但对于函数外创建的指针就无能为力了。
优点:对于在复杂的函数种,使用scoped_ptr 指针能够帮助我们处理那些容易忘记释放的对象。也因此在调试模式下如果使用了空指针,就会出现一个断言。
3、引用指针计数器
引用指针计数器记录有多少个引用指针指向同一个对象,如果最后一个引用指针被销毁的时候,那么就销毁对象本身。
shared_ptr 就是Boost中普通的引用指针计数器,它表示可以有多个指针指向同一个对象,看下面的例子:
void Sample2_Shared()
{
// (A)创建Csample类的一个实例和一个引用。
boost::shared_ptr
printf("The Sample now has %i references\n", e_count()); // The
Sample now has 1 references
// (B)付第二个指针给它。
boost::shared_ptr
printf("The Sample now has %i references\n", e_count());
// (C) 设置第一个指针为空。
mySample.reset();
printf("The Sample now has %i references\n", e_count()); // 一个引
用
// 当mySample2离开作用域的时候,对象只有一个引用的时候自动被删除。
}
在(A)中在堆栈重创建了CSample类的一个实例,并且分配了一个shared_ptr指针。对象mySample入下图所示:
然后我们分配了第二个指针mySample2,现在有两个指针访问同一个数据。
我们重置第一个指针(将mySample设置为空),程序中仍然有一个Csample实例,mySample2有一个引用指针。
只要当最有一个引用指针mySample2退出了它的作用域之外,Csample这个实例才被销毁。
当然,并不仅限于单个Csample这个实例,或者是两个指针,一个函数,下面是用shared_ptr的实例:
用作容器中。
∙用在PIMPL的惯用手法(the pointer-to-implementation idiom )。
∙RAII(Resource-Acquisition-Is-Initialization)的惯用手法中。
∙执行分割接口。
注意:如果你没有听说过PIMPL (a.k.a. handle/body) 和 RAII,可以找一个好的C++书,在C++中处于重要的内容,一般C++程序员都应该知道(不过我就是第一次看到这个写法)。智能指针只是一中方便的他们的方法,本文中不讨论他们的内容。
PIMPL:如果必须包容一个可能抛异常的子对象,但仍然不想从你自己的构造函数中抛出异常,考虑使用被叫做Handle Class或Pimpl的方法(“Pimpl”个双关语:pImpl或“pointer to implementation”)
4、主要特点
boost::shared_ptr 有一些重要的特征必须建立在其它操作之上。
∙shared_ptr
当声明或定义一个shared_ptr
∙shared_ptr
在这里本质上不需要制定T的类型(如从一个基类继承下来的)
∙shared_ptr
如果你的类中自己写了释放方法,也可以使用。具体参照Boost文档。
∙强制转换
如果你定义了一个U*能够强制转换到T*(因为T是U的基类),那么shared_ptr也能够强制转换到shared_ptr
∙shared_ptr 是线程安全的
(这种设计的选择超过它的优点,在多线程情况下是非常必要的)
∙已经作为一种惯例,用在很多平台上,被证明和认同的。
5、例子:在容器中使用shared_ptr
许多容器类,包括STL,都需要拷贝操作(例如,我们插入一个存在的元素到list,vector,或者container。)当拷贝操作是非常销毁资源的时候(这些操作时必须的),典型的操作就是使用容器指针。
std::vector
vec.push_back( new CMyLargeClass("bigString") );
将内存管理的任务抛给调用者,我们能够使用shared_ptr来实现。
typedef boost::shared_ptr
std::vector
vec.push_back( CMyLargeClassPtr(new CMyLargeClass("bigString")) );
当vector被销毁的时候,这个元素自动被销毁了。当然,除非有另一个智能指针引用了它,则还本能被销毁。让我们看Sample3中的使用:
void Sample3_Container()
{
typedef boost::shared_ptr
// (A) create a container of CSample pointers:
std::vector
// (B) add three elements
vec.push_back(CSamplePtr(new CSample));
vec.push_back(CSamplePtr(new CSample));
vec.push_back(CSamplePtr(new CSample));
// (C) "keep" a pointer to the second:
CSamplePtr anElement = vec[1];
// (D) destroy the vector:
vec.clear();