您的位置:首页 > 编程语言 > C语言/C++

C++中的智能指针

2016-04-10 20:54 295 查看
当设计含有指针的类时,应特别小心。因为指针指向的对象通常不包含在类的对象中,当类对象进行复制时,默认复制构造函数通常是浅拷贝(bitwise copy),只是拷贝了指针的值,这是两个指针指向同一个对象。通过其中一个指针就可以改变对象的值,也可以释放指针指向的对象;这时候另一个指针并不知情。引用C++ Primer的例子

[cpp] view
plain copy

 





class HasPtr{  

public:  

        HasPtr(int *p, int i):ptr(p),val(i){}  

        //获取成员变量的接口  

        int *get_ptr()const { return ptr;}  

        int get_int const {return val;}  

        //设置成员变量的接口  

        void set_per(int *p){ptr=p;}  

        void set_int(int i){val=i;}  

          

        int get_ptr_val()const {return *ptr;}  

        int set_ptr_val(int val)const {*prt=val;}//指针的值没变,所以可以为const          

private:  

    int *ptr;  

    int val;  

}  

按照如下使用:

[cpp] view
plain copy

 





int *ip=new int(42);  

HasPtr prt1(ip,42);  

HasPtr ptr2(ptr1);//bitwise copy  

这时ptr1和ptr2中的指针指向同一个对象。假如有一个对象释放,运行析构函数(如果有的话),另一个对象中的指针将成为悬浮指针,而这个对象对此毫不知情。

为了避免类似的事情发生,C++中给我们提供了智能指针。智能指针的本质是使用一个类来管理指针。在这个类里面加了一个变量--引用计数,记录与指针对象关联的类的个数。只有当引用计数为零时,才可以释放指针指向的对象。智能指针的行为要和普通指针一样。但是智能指针多了引用计数,当引用指针类的个数发现变化时(比如复制构造函数和复制操作符),引用计数要体现出这样变换。例如,在复制构造函数中,引用计数应加1。而在赋值操作符(重载)中,左操作数使用的智能指针引用计数减1 ,而右操作数使用的智能指针引用计数加1。下一个问题就是要把这个引用计数放到哪里?可以放到类HasPtr中吗?如果放到HasPtr中

class HasPtr{

……

private:

int *ptr;int val;

size_t use;//引用计数

}
这样每个对象中就会有引用计数,当我们更新引用计数时,要更新每个对象中的use值,实在难以实现。

但是真的不能放到HasPtr中吗?只要确保每个对象都能知道引用计数的值,有能确保引用计数容易更新,就可以。方法是使用指针(指针型句柄就是这样做的)。

[cpp] view
plain copy

 





class HasPtr{  

……        

private:  

    int *ptr;  

    int val;  

    size_t *use;//引用计数  

}  

C++ Primer给我们的例子是使用计数类。

[cpp] view
plain copy

 





class U_Ptr{  

    friend class HasPtr;  

    int *ip;  

    size_t use;  

    U_Ptr(int *P):ip(p),use(1){}  

    ~U_Ptr(){ delete ip;}  

}  

HasPtr为友元。计数器类中的变量都为private。

使用智能指针类,要像使用普通指针一样,所以要重新设计HasPtr类

[cpp] view
plain copy

 





class HasPtr{  

public:  

        HasPtr(int *p, int i):ptr(new U_Ptr(p)),val(i){}  

              

        //重新实现复制否造函数  

        HasPtr(const HasPtr &orig):  

            ptr(orig.ptr),val(orig.val){++ptr->use;}  

        HasPtr&operator=(const HasPtr& rhs);  

        //获取成员变量的接口  

        int *get_ptr()const { return ptr->ip;}  

        int get_int const {return val;}  

        //设置成员变量的接口  

        void set_per(int *p){ptr->ip=p;}  

        void set_int(int i){val=i;}  

          

        int get_ptr_val()const {return *ptr->ip;}  

        int set_ptr_val(int val)const {*prt->ip=val;}//指针的值没变,所以可以为const       

          

private:  

    U_Ptr *ptr;  

    int val;  

}  

//实现赋值操作符重载  

HasPtr& HasPtr::operator=(const HasPtr &rhs)  

{  

    ++rhs.prt->use++;//右操作数智能指针的引用计数加1  

    if(--ptr->use==0)//左操作数智能指针的引用计数减1  

        delete ptr;  

    ptr=rhs.ptr;  

    val=rhs.val;  

    return *this;  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: