当前位置:文档之家› 智能指针

智能指针

在你的代码中使用Boost智能指针Smart Pointers to boost your code(By peterchen)翻译 masterleeDownload source files - 45.3kb正文智能指针能够使C++的开发简单化,主要是它能够像其它限制性语言(如C#、VB)自动管理内存的释放,而且能够做更多的事情。

1、什么是智能指针智能指针是一种像指针的C++对象,但它能够在对象不使用的时候自己销毁掉。

我们知道在C++中的对象不再使用是很难定义的,因此C++中的资源管理是很复杂的。

各种智能指针能够操作不同的情况。

当然,智能指针能够在任务结束的时候删除对象,除了在程序之外。

许多库都提供了智能指针的操作,但都有自己的优点和缺点。

Boost库是一个高质量的开源的C++模板库,很多人都考虑将其加入下一个C++标准库的版本中。

下面让我们看一个简单的例子:2、首先介绍:boost::scoped_ptr<T>scoped_ptr 是 Boost 提供的一个简单的智能指针,它能够保证在离开作用域后对象被释放。

例子说明:本例子使用了一个帮助我们理解的类: CSample, 在类的构造函数、赋值函数、析构函数中都加入了打印调试语句。

因此在程序执行的每一步都会打印调试信息。

在例子的目录里已经包含了程序中需要的Boost库的部分内容,不需要下载其它内容(查看Boost的安装指南)。

使用普通普通指针的时候,我们必须记住在函数退出的时候要释放在这个函数内创建的对象。

当我们使用例外的时候处理指针是特别烦人的事情(容易忘记销毁它)。

使用scoped_ptr 指针就能够在函数结束的时候自动销毁它,但对于函数外创建的指针就无能为力了。

优点:对于在复杂的函数种,使用scoped_ptr 指针能够帮助我们处理那些容易忘记释放的对象。

也因此在调试模式下如果使用了空指针,就会出现一个断言。

3、引用指针计数器引用指针计数器记录有多少个引用指针指向同一个对象,如果最后一个引用指针被销毁的时候,那么就销毁对象本身。

shared_ptr 就是Boost中普通的引用指针计数器,它表示可以有多个指针指向同一个对象,看下面的例子:void Sample2_Shared(){// (A)创建Csample类的一个实例和一个引用。

boost::shared_ptr<CSample> mySample(new CSample);printf("The Sample now has %i references\n", e_count()); // TheSample now has 1 references// (B)付第二个指针给它。

boost::shared_ptr<CSample> mySample2 = mySample; // 现在是两个引用指针。

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<T>作用在一个未知类型上当声明或定义一个shared_ptr<T>,T可能是一个未知的类型。

例如你仅仅在前面声明了class T,但并没有定义class T。

当我们要释放这个指针的时候我们需要知道这个T具体是一个声明类型。

∙shared_ptr<T>作用在任意类型上在这里本质上不需要制定T的类型(如从一个基类继承下来的)∙shared_ptr<T>支持自己定义释放对象的操作如果你的类中自己写了释放方法,也可以使用。

具体参照Boost文档。

∙强制转换如果你定义了一个U*能够强制转换到T*(因为T是U的基类),那么shared_ptr<U>也能够强制转换到shared_ptr<T>。

∙shared_ptr 是线程安全的(这种设计的选择超过它的优点,在多线程情况下是非常必要的)∙已经作为一种惯例,用在很多平台上,被证明和认同的。

5、例子:在容器中使用shared_ptr许多容器类,包括STL,都需要拷贝操作(例如,我们插入一个存在的元素到list,vector,或者container。

)当拷贝操作是非常销毁资源的时候(这些操作时必须的),典型的操作就是使用容器指针。

std::vector<CMyLargeClass *> vec;vec.push_back( new CMyLargeClass("bigString") );将内存管理的任务抛给调用者,我们能够使用shared_ptr来实现。

typedef boost::shared_ptr<CMyLargeClass> CMyLargeClassPtr;std::vector<CMyLargeClassPtr> vec;vec.push_back( CMyLargeClassPtr(new CMyLargeClass("bigString")) );当vector被销毁的时候,这个元素自动被销毁了。

当然,除非有另一个智能指针引用了它,则还本能被销毁。

让我们看Sample3中的使用:void Sample3_Container(){typedef boost::shared_ptr<CSample> CSamplePtr;// (A) create a container of CSample pointers:std::vector<CSamplePtr> vec;// (B) add three elementsvec.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();// (E) the second element still existsanElement->Use();printf("done. cleanup is automatic\n");// (F) anElement goes out of scope, deleting the last CSample instance}6、使用Boost中的智能指针,什么是正确的使用方法使用智能指针的一些操作会产生错误(突出的事那些不可用的引用计数器,一些对象太容易释放,或者根本释放不掉)。

Boost增强了这种安全性,处理了所有潜在存在的危险,所以我们要遵循以下几条规则使我们的代码更加安全。

下面几条规则是你应该必须遵守的:规则一:赋值和保存——对于智能指针来说,赋值是立即创建一个实例,并且保存在那里。

现在智能指针拥有一个对象,你不能手动释放它,或者取走它,这将帮助你避免意外地释放了一个对象,但你还在引用它,或者结束一个不可用的引用计数器。

规则二:_ptr<T>不是T*——恰当地说,不能盲目地将一个T* 和一个智能指针类型T相互转换。

意思是:∙当创建一个智能指针的时候需要明确写出__ptr<T> myPtr<new T>。

∙不能将T*赋值给一个智能指针。

∙不能写ptr = NULL,应该使用ptr.reset()。

∙重新找回原始指针,使用ptr.get(),不必释放这个指针,智能指针会去释放、重置、赋值。

使用get()仅仅通过函数指针来获取原始指针。

∙不能通过T*指向函数指针来代表一个__ptr<T>,需要明确构造一个智能指针,或者说将一个原始指针的所有权给一个指针指针。

(见规则三)∙这是一种特殊的方法来认定这个智能指针拥有的原始指针。

不过在Boost:smart pointerprogramming techniques举例说明了许多通用的情况。

规则三:非循环引用——如果有两个对象引用,而他们彼此都通过一个一个引用指针计数器,那么它们不能释放,Boost 提供了weak_ptr来打破这种循环引用(下面介绍)。

规则四:非临时的share_ptr ——不能够造一个临时的share_ptr来指向它们的函数,应该命名一个局部变量来实现。

(这可以使处理以外更安全,Boost share_ptr best practices有详细解说)。

相关主题