智能指针实现
简介
智能指针是一个类,它对普通指针进行封装,使智能指针对象具有普通指针类型一样的操作。它能够在复制对象时,使副本和原对象都指向同一存储区域,通过副本或原对象改变所指值时,通过另一个对象访问的值也发生改变。
智能指针能够对内存进行自动管理,避免出现悬垂指针情况。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; }
参看文献