本文共 4761 字,大约阅读时间需要 15 分钟。
C、C++没有自动内存回收机制,程序员需要手动释放,如果忘记则会导致内存泄露,另外普通指针存在悬垂指针的问题。
当有多个指针指向同一个对象时,如果某个指针delete了该对象,对这个指针来说它是明确了它所指的对象被释放了,所以它不会再对此对象进行操作,但是对于剩下的其他指针来说呢?它们还傻傻地指向已经被删除的对象,并随时准备对它进行操作,于是悬垂指针就形成了。
/************************************************************************* > File Name: 悬垂指针.cpp > Author: Tanswer_ > Mail: 98duxm@gmail.com > Created Time: 2016年10月10日 星期一 19时33分44秒 ************************************************************************/#include#include #include #include #include #include #include #include #include #include #include using namespace std;int main(){ //shared_ptr p1; int *ptr1 = new int(1); int *ptr2 = ptr1; int *ptr3 = ptr2; cout << *ptr1 << endl; cout << *ptr2 << endl; cout << *ptr3 << endl; delete ptr1; cout << *ptr2 << endl; return 0;}
代码很简单,我们可以看出错误产生来自ptr1并不知道还有其他指针共享着它所指向的对象,如果想办法让ptr1知道,除了自己外还有其他两个指针指向该对象,那么它不删除对象,问题就得到解决。
智能指针的一种通用实现技术是使用引用计数器,智能指针类将一个计数器与类所指的对象相关联,引用计数器跟踪该类有多少个对象共享同一指针。
具体做法:
1).每次创建类的新对象时,初始化指针并将引用计数置为1; 2).当对象作为另一个对象的副本时,复制构造函数复制副本指针,并增加与指针引用相应的引用计数(加1); 3).使用赋值操作符对一个对象进行赋值时,处理复杂一点:先使左操作数的指针的引用计数减1(因为指针已经指向别的地方),如果减1后引用计数为0,则释放指针所指对象内存。然后增加右操作数所指对象的引用计数(因为此时左操作数指向对象即右操作数指向对象)。 4).析构函数:调用析构函数时,析构函数先使引用计数减1,如果减至0则delete对象。1.为了直观的表示,我们实例化一个基础对象--点
//基础对象类class Point{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; }private: int x; int y;};
2.辅助类
/* * 辅助类,成员全部是私有,只为智能指针使用 * 用以封装使用计数与基础对象指针*/class U_ptr{private: friend class SmartPtr; U_ptr(Point *ptr): p(ptr),count(1) {} ~U_ptr() { delete p; } int count; //计数 Point *p; //基础对象指针};
3.为基础对象类实现智能指针类: 按以上介绍引用计数的做法,以引用计数为关键点
class SmartPtr{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; }private: U_ptr *rp;};
4.主函数
int main(){ //定义一个基础对象指针 Point *pa = new Point(10,20); //定义三个智能指针类对象,都指向基础类对象pa //使用花括号控制三个指针的生命期,观察计数的变化 { SmartPtr sptr1(pa); //此时count = 1 { SmartPtr sptr2(sptr1); //调用复制构造函数 count = 2 { SmartPtr sptr3 = sptr1; //调用赋值操作符 count = 3 }//count = 2 } //count = 1 }//count = 0 pa 被delete cout << pa-> getX() << endl; return 0;}
输出结果:
还有2 个指针指向基础对象还有1 个指针指向基础对象0
上述程序实现的智能指针不能像 正常指针那样有 * -> 等操作符,而且只是适应Point这个类对象,下面我们完成一个完整的智能指针,重载* -> 等操作符,用类模板来使我们的智能指针适用于更多的基础对象类。
/************************************************************************* > File Name: 智能指针_3.cpp > Author: Tanswer_ > Mail: 98duxm@gmail.com > Created Time: 2016年10月10日 星期一 20时53分45秒 ************************************************************************///前两个例子只能用于管理Point类的基础对象//本例中我们设计模板 使我们的智能指针适用于更多的基础对象类#include#include #include #include #include #include #include #include #include #include using namespace std;//基础对象类class Point{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; }private: int x; int y;};/* * 辅助类,成员全部是私有,只为智能指针使用 * 用以封装使用计数与基础对象指针*///模板类作为友元时要先有声明template class SmartPtr;template class U_ptr{private: //该类成员访问权限全部为private,因为不想让用户直接使用该类 friend class SmartPtr ; //因为智能指针需要直接操纵辅助类 //构造函数的参数为基础对象的指针 U_ptr(T *ptr): p(ptr),count(1) {} ~U_ptr() { delete p; } //引用计数 int count; //基础对象指针 T *p;};template class SmartPtr //智能指针类{public: SmartPtr(T *ptr) :rp(new U_ptr (ptr)) {} //构造函数 /*复制构造函数*/ SmartPtr(const SmartPtr &sp) :rp(sp.rp) { ++rp->count; } //重载赋值操作符 SmartPtr& operator=(const SmartPtr & rhs) { ++rhs.rp->count; //首先将右操作数计数加1 if(--rp->count == 0) delete rp; rp = rhs.rp; return *this; } ~SmartPtr() { if(--rp->count == 0) //当引用计数减为0,释放指针,删除对象 delete rp; else cout << "还有" << rp->count << " 个指针指向基础对象" << endl; } T & operator *() //重载*操作符 { return *(rp->p); } T * operator ->() //重载->操作符 { return rp->p; }private: U_ptr *rp; //辅助类对象指针};int main(){ int *i = new int(2); { SmartPtr ptr1(i); { SmartPtr ptr2(ptr1); { SmartPtr ptr3 = ptr1; cout << *ptr1 << endl; *ptr1 = 20; cout << *ptr2 << endl; } } } return 0;}
输出结果为:
220还有2 个指针指向基础对象还有1 个指针指向基础对象
OK~~~
此外,C++11新的标准库提供了两种智能指针类型来管理动态对象。转载地址:http://yluoi.baihongyu.com/