我们知道当我们在堆空间中申请了一片内存后如果使用完毕后就应该释放,否则就会造成内存泄漏。这是所有程序员都基本知道的一个问题,即便都知道但还是出现了大量的因内存泄漏而导致的BUG,C++中并没有像Java语言中存在垃圾回收机制,而且指针还不能控制所指堆空间的生命周期,因为指针本身只是一个变量,它和堆空间的内存并没有任何关系,指针没了,但是堆空间还存在,既然C++是一门更贴近于生活的语言那么就应该对此作出一定的对策,首先我们应该思考我们需要什么功能来防止内存泄漏?
我们需要的是一个特殊的指针,这个指针能够在生命周期结束时自动 释放堆空间,并且每一片堆空间只能由一个指针来标识,避免同一片空间多次释放,并且得杜绝指针运算和指针比较,因为进行指针运算时很可能导致越界而得到一个野指针,要是满足了这些功能后指针比较在这里也就毫无意义。C++中给这个功能提供了一个很好听的名字---智能指针。
那么知道了需求后就该想着手干了。解决方案就是重载,我们可以通过操作符重载来模拟指针的行为,我们可以定义一个对象,让这个对象模拟真正的指针的操作行为。C/C++中有两个操作指针的操作符,->和* ,操作指针必然会用到这两个操作符,我们可以对这两个操作符进行重载,然后使用对象来模拟指针,那么要重载他们应该注意哪些规定?
1.、只能通过类的成员函数重载
2、重载函数不能使用参数,所以重载函数只有一个。
知道了规则就该编写一个智能指针类了。
我们需要实现两个类,一个普通类,一个智能指针类。
class Test
{
int i;
public:
Test(int i)
{
cout << "Test(int i)" << i <<endl;
this->i = i;
}
int getvalue()
{
return i;
}
~Test()
{
cout << "~Test()" << endl;
}
};
class Pointer
{
Test* mp;
public:
Pointer(Test* p = NULL)
{
mp = p;
}
Pointer(const Pointer& obj)
{
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;//const对象成员变量不能直接修改
}
Pointer& operator = (const Pointer& obj)
{
if( this != &obj )
{
delete mp;
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
}
return *this;
}
Test* operator -> ()
{
return mp;
}
Test& operator * ()
{
return *mp;
}
bool isNull()
{
return (mp == NULL);
}
~Pointer()
{
delete mp;
}
};
Test类里面很简单,一个私有变量,一个构造函数、一个析构函数、一个获取成员变量值的普通成员函数。
在智能指针类pointer中,首先有一个私有的Test类型的指针变量,首先是一个构造函数,初始化成员变量,默认值为NULL,然后对指针操作符进行重载,重载->操作符返回的是Test指针,对*操作符重载返回的是指针所指的对象,即返回一个Test引用,类中为了自动释放堆空间内存,所以可以在析构函数中delete,因为析构函数自动调用。由于只能由一个指针标识堆空间,我们需要添加拷贝构造函数和对赋值操作符进行重载,在进行拷贝构造函数实现中首先将初始化对象指向的空间赋值过来,然后将初始化对象指向的空间置为NULL,这样就转移了堆空间的管理权,赋值操作符的重载函数实现在遵循四小点的前提下和拷贝构造函数的实现基本一致,最后一个成员函数,判断当前对象指向的空间是否为NULL。这样智能指针类就算实现完了,接下来就是如何使用了。
Pointer p1 = new Test(100);
cout << p1->value() << endl;
Pointer p2 = p1;
cout << p1.isNull() << endl;
cout << p2->value() << endl;
Pointer p3 = new Test(2);
p2 = p3;
cout << p2->value() << endl;
cout << p3.isNull() << endl;
输出结果为:
Test(int i)100
100
1
100
Test(int i)2
~Test()
2
1
~Test()
为什么呢?
首先创建对象p1初始化为100,然后输出p1指向对象成员变量的值,然后创建了对象p2,由p1初始化,所以会调用拷贝构造函数,p2指向原先p1指向的空间,p1将指向NULL;第四条语句判断智能指针p1是否为空,答案是肯定的,表示一个堆空间确实只能由一个指针标识,然后打印了p2指向对象的成员变量值,为原先p1对象成员变量的值,初始化是成功的。最后一个操作就是重新创建了一个对象p3,将它赋值给p2,输出p2的值和p3的状态,发现赋值是成功的,并且p3也释放了它对对象的管理权。
本身还需要测试指针运算和比较的,由于使用了编译会报错就不贴出来了。
当我们学习了模板技术后就能使这里的职能指针能够适用于各种类了。
智能指针只能指向堆空间的变量或对象。
智能指针对象能够代替指针。
使用智能指针能够最大程度的避免内存问题。