C++智能指针scoped_ptr的原理和使用

scoped_ptr是一个类似于auto_ptr的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确的删除。但是scoped_ptr的所有权更加严格,不能转让,一旦scoped_pstr获取了对象的管理权,你就无法再从它那里取回来。

正如scoped_ptr(局部指针)名字的含义:这个智能指针只能在作用域里使用,不希望被转让。

代码实现如下:

template<class T>
class scoped_ptr{
private:
    T *px;
    scoped_ptr(scoped_ptr const &);
    scoped_ptr & operator=(scoped_ptr const &);
public:
    explicit scoped_ptr(T *p = 0);
    ~scoped_ptr();

    void reset(T *p = 0);

    T & operator*()const;
    T * operator->()const;
    T * get()const;

    operator unspecified-bool-type()const;
    void swap(scoped_ptr & b);
};

可见,scoped_str的构造函数接受一个类型为T*的指针p,创建出一个scoped_ptr对象,并在内部保存指针参数p。p必须是一个new表达式动态分配的结果,或者是一个空指针(0)。当scoped_ptr对象的生命周期结束时,析构函数~scoped_ptr()会使用delete操作自动销毁所保存的指针对象,从而正确的回收资源。

scoped_ptr同时把拷贝构造函数和赋值操作都声明为私有的,禁止对智能指针的复制操作,保证了被它管理的指针不能被转让所有权。

成员函数reset()的功能是重置scoped_ptr;它删除原来报存的指针,再保存新的指针值p。如果p是空指针,那么scoped_ptr将不能持有任何指针。一般情况下reset()不应该被调用,因为它违背了scopd_ptr的本意——资源应该一直由scopd_ptr自己自动管理。

void reset(_Ty * p = 0)  //never throw
{
    this_type(p).swap(*this);
}

实际上拥有权不可转移不够方便,swap()成员函数可以交换两个scopd_ptr保存的原始指针。

 template<typename T> void swap(scoped_ptr<T>& a,scoped_ptr<T>& b)
 void swap(scoped_ptr & b)
 {
    _Ty * tmp = b.px;
    b.px = px;   //tmp临时变量在交换后被释放
    px = tmp;    //保证只被一个智能指针管理
 }

函数提供了交换两个scoped pointer的内容的更好的方法。之所以说它更好,是因为swap(scoped1,scoped2) 可以更广泛地用于很多指针类型,包括裸指针和第三方的智能指针。scoped1.swap(scoped2) 则只能用于它的定义所在的智能指针,而不能用于裸指针。

scoped_ptr用operator*()和operator->()重载了引用操作符*和箭头操作符->,以模仿被代理的原始指针的行为,因此可以把scopd_ptr对象如同指针一样的使用。如果scopd_ptr保存空指针,那么这两个操作都是未定义的。

scopd_ptr不支持比较操作,不能在两个scopd_ptr之间,scopd_ptr和原始指针之间或空指针之间进行相等或者不等的操作,我们也无法为它编写额外的比较函数,因为它已经将operator== 和 operator!=两个操作符声明为私有的。

成员函数讲解

explicit scoped_ptr(T* p=0)
构造函数,存储p的一份拷贝。注意,p 必须是用operator new分配的,或者是null. 在构造的时候,不要求T必须是一个完整的类型。当指针p是调用某个分配函数的结果而不是直接调用new得到的时候很有用:因为这个类型不必是完整的,只需要类型T的一个前向声明就可以了。这个构造函数不会抛出异常。

~scoped_ptr()
删除指针所指向的对象。类型T在被销毁时必须是一个完整的类型。如果scoped_ptr在它被析构时并没有保存资源,它就什么都不做。这个析构函数不会抛出异常。

void reset(T* p=0);
重置一个 scoped_ptr 就是删除它已保存的指针,如果它有的话,并重新保存p. 通常,资源的生存期管理应该完全由scoped_ptr自己处理,但是在极少数时候,资源需要在scoped_ptr的析构之前释放,或者scoped_ptr要处理它原有资源之外的另外一个资源。这时,就可以用reset,但一定要尽量少用它。(过多地使用它通常表示有设计方面的问题) 这个函数不会抛出异常。

T& operator*() const;
该运算符返回一个智能指针中存储的指针所指向的对象的引用。由于不允许空的引用,所以解引用一个拥有空指针的scoped_ptr将导致未定义行为。如果不能肯定所含指针是否有效,就用函数get替代解引用。这个函数不会抛出异常。

T* operator->() const;
返回智能指针所保存的指针。如果保存的指针为空,则调用这个函数会导致未定义行为。如果不能肯定指针是否空的,最好使用函数get。这个函数不会抛出异常。

T* get() const;
返回保存的指针。应该小心地使用get,因为它可以直接操作裸指针。但是,get使得你可以测试保存的指针是否为空。这个函数不会抛出异常。get通常在调用那些需要裸指针的函数时使用。

operator unspecified_bool_type() const
返回scoped_ptr是否为非空。返回值的类型是未指明的,但这个类型可被用于Boolean的上下文(boolean context)中。在if语句中最好使用这个类型转换函数,而不要用get去测试scoped_ptr的有效性。

void swap(scoped_ptr& b)
交换两个scoped_ptr的内容。这个函数不会抛出异常。

用法

scoped_ptr的用法与普通的指针几乎没什么区别;最大的差别在于你不必再记得在指针上调用delete,还有复制是不允许的。典型的指针操作(operator* 和 operator->)都被重载了,并提供了和裸指针一样的语法。用scoped_ptr和用裸指针一样快,也没有大小上的增加,因此它们可以广泛使用。使用boost::scoped_ptr时,包含头文件”boost/scoped_ptr.hpp”. 在声明一个scoped_ptr时,用被指物的类型来指定类模板的参数。例如,以下是一个包含std::string指针的scoped_ptr:
boost::scoped_ptr p(new std::string(“Hello”));
当scoped_ptr被销毁时,它对它所拥有的指针调用delete 。

与auto_ptr的区别

scoped_ptr的用法和auto_ptr几乎一样,大多数情况下它都可以与auto_ptr互相替换,它也可以从一个auto_ptr获得指针的管理权(同时auto_ptr失去管理权)。

scoped_ptr和auto_ptr一样不能用作容器的元素,但原因不同:auto_ptr是因为它的转移语义,而scoped_ptr则是因为不支持拷贝和赋值,不符合容器对元素类型的要求。

scoped_ptr和auto_ptr的根本区别在于所有权。auto_ptr特意被设计为指针的所有权是可以被转移的,可以在函数之间传递,同一时刻只能有一个auto_ptr管理指针。而scoped_ptr把拷贝构造函数和赋值函数都声明为私有的,拒绝了指针所有权的转让,只有scoped_ptr自己能够管理指针,其他任何人都无权访问被管理的指针,从而保证了指针的绝对安全。
如下代码所示:

auto_ptr<int> ap(new int(10)); //一个int自动指针
scoped_ptr<int>sp (ap);        //从auto_ptr获得原始指针
assert(ap.get() == 0);         //原auto_ptr不再拥有指针

ap.rest(new int(20));          //auto_ptr拥有新的指针
cout <<*ap<<","<<*sp<<endl;    

auto_ptr<int>ap2;
ap2 = ap;                      //ap2从ap获得原始指针,所有权转移
assert(ap.get() == 0);         //ap不再拥有原始指针
scoped_ptr<int>sp2;            //另一个scoped_ptr
sp2 = sp;                      //赋值操作,无法同过编译!

如果代码企图从一个scoped_ptr构造或赋值另一个scoped_ptr(最后一行),那么编译器会报错,阻止这么做,保护了你的代码。
比起auto_ptr,scoped_ptr更明确地表明了代码原始编写者的意图;只能在定义的作用域内使用,不可转让,这在代码后续的维护生命周期中很重要。

转自:http://blog.csdn.net/l953972252/article/details/51379615
学习:
[C++] Boost智能指针——boost::scoped_ptr(使用及原理分析)
scoped_ptr解析和总结

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值