智能指针就是一个类,对普通指针进行封装,使智能指针对象具有普通指针类型一样的操作。(智能指针是封装普通指针的一个类,声明的对象和指针有一样的操作) 复制对象时,副本和原对象都指向同一存储区域,如果通过一个副本改变其所指的值,则通过另一对象访问的值也会改变。所不同的是,智能指针能够对内存进行自动管理,避免出现悬垂指针等情况。
普通指针的悬垂问题:当有多个指针指向同一个基础对象时,如果某个指针delete了该基础对象,对这个指针来说他已经明确他所指的对象被释放了,所以不会再对所指的对象进行操作,但是对于其他的指针来说,他们并不知道这个对象已经被释放了,还会指向这个被释放掉的对象并随时准备对其进行操作,这就形成了悬垂指针,程序也会慢慢崩溃。
悬垂指针产生的原因:删除基础对象的指针不知道还有其他指针和他一起共享这个基础对象,所以他在不知道的情况下将基础对象删除,让和他一起共享这个被删除的基础对象的指针成为悬垂指针。
解决办法:添加一个引用计数,用来计数有多少个指针共享一个基础对象,当一个指针delete后,计数器减一,直到计数器为0,才释放该基础对象。
引用计数:允许有多个相同值的对象共享这个值的实现
目的:
- 简化跟踪堆(C++中new出来的)中对象的过程。一个对象一旦通过new被分配出来,要记录谁拥有该对象,因为其所有者要负责对其delete。但是对象所有者可以有多个,且所有权能够被传递,这就使得内存跟踪变得困难。引用计数可以跟踪对象所有权,并能够自动销毁对象。
- 节省内存,提高程序运行效率。如果很多对象拥有相同的值,那么为多个相同的值存储多个副本就会浪费空间,所以让左右对象共享同一个值的实现。
智能指针的实现:辅助类和句柄类
定义一个基础对象类Point类
class Point
{
public:
/*初始化成员变量:相当于Point(int xVal = 0, int yVal = 0) {this->x = xVal; this->y = yVal;}*/
Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) {
}
/*const修饰成员函数:1.该函数不能改变对象的成员变量。2.不能调用非const的成员函数,因为任何非const的成员函数会有
修改成员变量的企图。3.const的成员函数才能被被const类对象调用,因为const类对象只能调用const成员函数。4.const关键字
不能同时和static关键字使用。因为static关键字修饰静态成员函数,静态成员函数不含有this指针,即不能实例化,而const
成员函数必须具体到某一实例*/
int getX const
{
return x;
}
int getY const
{
return y;
}
void setX(int xVal)
{
x = xVal;
}
void setY(int yVal)
{
y = yVal;
}
prinvate:
int x;
int y;
};
在创建智能指针之前,先创建一个辅助类。这个类的所有成员都是私有类型,因为他不能被普通用户所使用。为了只让智能指针使用,还需要把智能指针声明为辅助类的友元。这个辅助类含有两个数据成员:计数count和智能对象指针。即辅助类用以封装使用计数和基础对象指针。
class U_Ptr
{
private:
/*类友元:类作为友元需要注意,友元类和原始类之间的相互依赖关系,如果在友元类中定义的函数访问原始类的私有变量,那么需要在
友元类定义文件中包含原始类定义的头文件。但是在原始类的定义中(包含友元类声明的类),不需要包含友元类的头文件。 另外,
不需要在类定义前去声明友元类,因为友元类的声明自身就是一种声明。*/
friend class SmartPtr; //智能指针声明为辅助类的友元,因为智能指针类需要直接操纵辅助类
U_Ptr(Point *ptr) :p(ptr),count(1) {
} //构造函数的参数为基础对象的指针
~U_Ptr() {
delete p;}
//两个数据成员:计数count,基础指针对象
int count;
Point *p;
};
引用计数是实现智能指针的一种通用方法。智能指针将