永恒的话题:
内存泄漏示例:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Test 7 { 8 int i; 9 public: 10 Test(int i) 11 { 12 this->i = i; 13 } 14 int value() 15 { 16 return i; 17 } 18 ~Test() 19 { 20 } 21 }; 22 23 int main() 24 { 25 for(int i=0; i<5; i++) 26 { 27 Test* p = new Test(i); 28 29 cout << p->value() << endl; 30 31 32 } 33 34 return 0; 35 }
这段程序我们没有释放堆空间,造成了内存泄漏。
深度的思考:
一片堆空间最多只能由一个指针标识,这可以避免多次释放。杜绝指针运算和比较可以避免野指针。
C++中不存在这样的指针,我们需要自己实现。
解决方案:
这四条都是硬性规定,最后两条说的是同一个问题。
程序与运行结果如下:
完善程序:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Test 7 { 8 int i; 9 public: 10 Test(int i) 11 { 12 cout << "Test(int i)" << endl; 13 this->i = i; 14 } 15 int value() 16 { 17 return i; 18 } 19 ~Test() 20 { 21 cout << "~Test()" << endl; 22 } 23 }; 24 25 class Pointer 26 { 27 Test* mp; 28 public: 29 Pointer(Test* p = NULL) 30 { 31 mp = p; 32 } 33 Pointer(const Pointer& obj) 34 { 35 mp = obj.mp; 36 const_cast<Pointer&>(obj).mp = NULL; 37 } 38 Pointer& operator = (const Pointer& obj) 39 { 40 if( this != &obj ) 41 { 42 delete mp; 43 mp = obj.mp; 44 const_cast<Pointer&>(obj).mp = NULL; 45 } 46 47 return *this; 48 } 49 Test* operator -> () 50 { 51 return mp; 52 } 53 Test& operator * () 54 { 55 return *mp; 56 } 57 bool isNull() 58 { 59 return (mp == NULL); 60 } 61 ~Pointer() 62 { 63 delete mp; 64 } 65 }; 66 67 int main() 68 { 69 Pointer p1 = new Test(0); 70 71 cout << p1->value() << endl; 72 73 Pointer p2 = p1; 74 75 cout << p1.isNull() << endl; 76 77 cout << p2->value() << endl; 78 79 return 0; 80 }
第49行重载的->和53行重载的*操作符没有参数,也没有重载,只定义一个,符合上面的最后两条要求。
重载拷贝构造函数和赋值操作符,使得一个内存空间只能由一个智能指针指向。
生成新对象才会调用拷贝构造函数,在拷贝构造函数中不能delete mp,因为这时候新生成的对象中mp还是野指针。
上述程序运行结果如下:
智能指针的使用军规:
只能用来指向堆空间中的对象或者变量。
小结: