1. 永恒的话题:内存泄漏
(1)动态申请堆空间,用完后不归还
(2)C++语言中没有垃圾回收的机制
(3)指针无法控制所指堆空间的生命周期
【编程实验】内存泄漏 37-1.cpp
#include <iostream> #include "IntArray.h" using namespace std; class Test { int i; public: Test(int i) { this->i = i; cout << "Test(int i)" << endl; } int value(){return i;} ~Test() { cout << "~Test()" << endl; } }; int main() { for(int i = 0; i < 5; i++) { Test* p = new Test(i); cout << p->value() << endl; //没有delete p造成内存泄漏 } return 0; }
运行结果:
2. 深度的思考:我们需要什么?
(1)需要一个特殊的指针,指针生命期结束时主动释放堆空间
(2)一片堆空间最多只能由一个指针来标识
(3)杜绝指针运算和指针比较(因为只有一个该类对象的指针能指向堆空间)
3. 解决方案
(1)重载指针特征操作符( -> 和 * )
(2)只能通过类的成员函数重载
(3)重载函数不能使用参数
(4)只能定义一个重载函数
(5)注意:智能指针只能用来指向堆空间中的对象或变量(不能指向栈)
【编程实验】智能指针 37-2.cpp
#include <iostream> #include "IntArray.h" using namespace std; class Test { int i; public: Test(int i) { this->i = i; cout << "Test(int i)" << endl; } int value(){return i;} ~Test() { cout << "~Test()" << endl; } }; //定义智能指针类 class Pointer { Test* mp;//用于保存要被管理对象的指针 public: Pointer(Test* p = NULL) { mp = p; } Pointer(const Pointer& obj) { mp = obj.mp; //当Pointer p2 = p1时,p1所指的堆空间由p2来接管 //即保证每次只能有一个智能指针指向同一堆空间 const_cast<Pointer&>(obj).mp = NULL; } Pointer& operator = (const Pointer& obj) { if( this != &obj) { delete mp; mp = obj.mp; //保证赋值操作时,只能由一个智能指针指向同一堆空间 const_cast<Pointer&>(obj).mp = NULL; } } //重载->操作符 Test* operator ->() //不能使用参数,所以也就只能定义一个重载函数 { return mp; } //重载*操作符 Test& operator*() //不能使用参数,所以也就只能定义一个重载函数 { return *mp; } bool isNull() { return (mp == NULL); } ~Pointer() { delete mp;//智能指针被析构时,同时删除其所管理的Test类的对象 } }; int main() { Pointer p1 = new Test(5); cout << p1->value() << endl; Pointer p2 = p1;//p2接管了p1所指的堆空间,保证每次只能由一个智能指针指向堆空间 cout << p1.isNull() << endl;//p1指向NULL了,不再指向原来的堆空间 cout << p2->value() << endl;//p2接管了p1所指堆空间 //p2++;不重载++,因为每次只能一个智能指针指向堆空间,这种++操作没意义 //p2智能指针生命期结束,会自动释放接管的堆空间 return 0; }
运行结果:
//输出结果:
//Test(int i)
//5
//1
//5
//~Test()
4. 小结
(1)指针特征操作符( -> 和 * )可以被重载
(2)重载指针特征符能够使用对象代替指针
(3)智能指针只能用于指向堆空间中的内存
(4)智能指针的意义在于最大程度的避免内存问题