智能指针实现

智能指针实现

  • 简介

    智能指针是一个类,它对普通指针进行封装,使智能指针对象具有普通指针类型一样的操作。它能够在复制对象时,使副本和原对象都指向同一存储区域,通过副本或原对象改变所指值时,通过另一个对象访问的值也发生改变。

    智能指针能够对内存进行自动管理,避免出现悬垂指针情况。C/C++语言中,在创建对象是进行内存分配,使用完毕后需要释放内存,如果出现不正确操作内存,则可能导致内存泄露。而智能指针能够解决这一问题,管理内存。

  • 引用计数

    引用计数让指针让要删除的内存知道是否还有其他指针存在,如果有,则不对内存进行删除,如有没有,则删除,这样能够避免悬垂指针的存在。

    引用计数的目的:

    1)简化跟踪堆中的对象的过程。它能够跟踪对象的所有权,并自动销毁对象。它充当简单垃圾回收体系。

    2)节省内存,提高程序运行效率。当很多对象有相同值时,共享这一值,避免复制存储多个副本,从而节省内存。

  • 实现

    智能指针的实现可以使用辅助类和句柄类两种策略实现。

    辅助类实现方法:定义一个基础对象类,然后在定义一个辅助类来实现。辅助类的所有成员均为私有,使其不被普通用户使用。为让智能指针使用,需把智能指针类声明为辅助类的友元。辅助类主要含有两个数据成员:计数count和基础对象指针。

    引用计数是实现智能指针的一种通用方法。智能指针将一个计数器与类指向的对象相关联,引用计数跟踪共有多少个类对象共享同一指针。具体做法:

    1)当创建类的新对象时,初始化指针,并将引用计数设置为1;

    2)当对象作为另一个对象的副本时,复制构造函数复制副本指针,并增加与指针相应的引用计数(加1);

    3)使用赋值操作符对一个对象进行赋值时,先使左操作数的指针的引用计数减1(减1是因为指针指向别的地方),如果减1后引用计数为0,则释放指针所指对象内存。然后增加右操作数所指对象的引用计数(增加是因为做操作数指向对象即右操作指向对象);

    4)调用析构函数时,析构函数先使引用计数减1,如果减至0,则delete对象。

    具体实现如下:

    #include <iostream>
    using namespace std;
    // 基础对象点类 
    class Point
    {
        private:
            int x, y;
        public:
            Point(int xVal = 0, int yVal = 0): x(xVal), y(yVal) { }
            int getX() const
            {
                return x;
            }
            int getY() const 
            {
                return y;
            }
            void setX(int xVal)
            {
                x = xVal;
            }
            void setY(int yVal)
            {
                y = yVal;
            }
    }; 
    
    // 辅助类
    class U_Ptr
    {
        private:
            int count;
            Point *p;
    
            friend class SmartPtr;
            U_Ptr(Point *ptr): p(ptr), count(1) { }
            ~U_Ptr() { delete p; }
    }; 
    
    class SmartPtr
    {
        private:
            U_Ptr *rp;
        public:
            SmartPtr(Point *ptr): rp(new U_Ptr(ptr)){ }
            SmartPtr(const SmartPtr &sp): rp(sp.rp)
            {
                ++rp->count;
            }
            SmartPtr& operator= (const SmartPtr& rhs)
            {
                ++rhs.rp->count;
                if (--rp->count == 0)
                    delete rp;
                rp = rhs.rp;
                return *this;
            }
            ~SmartPtr()
            {
                if (--rp->count == 0)
                    delete rp;
                else
                    cout << "还存在" << rp->count << "个指针指向基础对象" << endl; 
            }
            Point& operator *()   // 重载*操作符
            {
                return *(rp->p);
            } 
            Point* operator ->()  // 重载->操作符
            {
                return rp->p;
            } 
    };
    
    int main()
    {
        // 定义一个基础对象类指针
        Point *pa = new Point(10, 20);
        // 定义三个智能指针类对象,对象都指向基础类对象pa
        // 使用花括号控制三个指针的生命期,观察技术的变化
        {
            SmartPtr sptr1(pa);               // 此时计数count = 1 
            cout << sptr1->getX() << endl;
            {
                SmartPtr sptr2(sptr1);        // 次时计数count = 2 
                {
                    SmartPtr sptr3 = sptr1;   // 此时技术count = 3 
                }
                // 此时count = 2; 
            }
            // 此时count = 1; 
        } 
        // 此时count = 0;pa对象被delete掉 
        cout << pa->getX() << endl;
        return 0;
    }
    

    利用模板实现

    #include <iostream>
    using namespace std;
    // 模板类作为友元时要先有声明
    template <typename T> class SmartPtr;
    
    // 辅助类
    template <typename T> class U_Ptr
    {
        // 类内成员访问权限为private,使其不让普通用户使用该类。 
        private:
            T *p;           // 基础对象指针
            int count;      // 引用计数 
            friend class SmartPtr<T>;           // 定义智能指针类为友元,因为智能指针类需要直接操作辅助类 
            U_Ptr(T *ptr):p(ptr),count(1) { }   // 构造函数的参数为基础对象的指针 
            ~U_Ptr() { delete p; }              // 析构函数 
    };
    // 智能指针类
    template <typename T> class SmartPtr
    {
        private:
            U_Ptr<T> *rp;   // 辅助类对象指针  
        public:
            SmartPtr(T *ptr):rp(new U_Ptr<T>(ptr)) { }   // 构造函数 
            SmartPtr(const SmartPtr<T> &sp):rp(sp.rp)    // 复制构造函数 
            { 
                ++rp->count;
            } 
            SmartPtr& operator = (const SmartPtr<T> &rhs)// 重载赋值操作符 
            {
                ++rhs.rp->count;       // 将右操作数引用计数加1 
                if (--rp.count == 0)   // 将左操作数引用计数减1,可以对应自赋值 
                    delete rp;
                rp = rhs.rp;
                return *this; 
            }
            T& operator *()            // 重载*操作符 
            {
                return *(rp->p);
            }
            T* operator ->()           // 重载->操作符
            {
                return rp->p;
            } 
            ~SmartPtr()                // 析构函数 
            {
                if (--rp->count == 0)  // 当引用计数减为0时,删除辅助类对象指针,从而删除基础对象 
                    delete rp;
                else
                    cout << "还存在" << rp->count << "个指针指向基础对象" << endl; 
            }
    }; 
    int main()
    {
        int *i = new int(2);
        {
            SmartPtr<int> ptr1(i);
            {
                SmartPtr<int> ptr2(ptr1);
                {
                    SmartPtr<int> ptr3 = ptr2;
                    cout << *ptr1 << endl;
                    *ptr1 = 20;
                    cout << *ptr2 << endl;
                } 
            }
        }
        return 0;
    }
    
  • 参看文献

    http://mp.weixin.qq.com/s?__biz=MzAxNDI5NzEzNg==&mid=2651156666&idx=1&sn=4109903d526468f5913922d2f06e5a1a&scene=23&srcid=0528aIzOIN05Z0MQKuw7HrwJ#rd

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值