C++中的智能指针类模板
1,智能指针本质上是一个对象,这个对象可以像原生的指针一样使用,因为智能指 针相关的类通过重载的技术将指针相关的操作符都进行了重载,所以智能指针对象可以像原生指针一样操作,今天学习智能指针类模板,通过这个类模板就可以淘汰原生的指针了;
2,智能指针的意义:
1,现代 C++ 开发库中最重要的类模板之一;
1,STL 标准库提供;
2,Qt 平台提供;
2,是 C++ 中自动内存管理的主要手段;
3,能够在很大程度上避开内存相关的问题;
1,内存泄漏,测试阶段很难发现,应用程序运行很久才能够发现,一般是申请堆空间内存忘记释放造成的;
2,多次指针释放,结果也是不确定的,有可能程序马上死掉,有可能过一段时间死掉并且这是就无法找问题究竟出在哪一行代码上;
3,STL 中的智能指针 auto_ptr:
1,生命周期结束时,销毁指向的内存空间;
1,智能指针是一个对象,有生命周期,这个特点解决内存泄漏问题;
2,不能指向堆数组,只能指向堆对象(变量);
1,这是一个缺点,但是另一个角度来看,使用堆空间的数组可以使用其他的类,比如上节课中的 HeapArray 类;
3,一片堆空间只属于一个智能指针对象;
1,避免多次释放同一个指针;
4,多个智能指针对象不能指向同一片堆空间;
1,同上面一点;
4,auto_ptr 使用初探:
1,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 #include <memory> // 智能指针类模板头文件所在头文件; 4 5 using namespace std; 6 7 class Test 8 { 9 string m_name; 10 public: 11 Test(const char* name) 12 { 13 cout << "Hello, " << name << "." << endl; 14 15 m_name = name; 16 } 17 18 void print() 19 { 20 cout << "I'm " << m_name << "." << endl; 21 } 22 23 ~Test() 24 { 25 cout << "Goodbye, " << m_name << "." << endl; 26 } 27 }; 28 29 int main() 30 { 31 auto_ptr<Test> pt(new Test("D.T.Software")); 32 33 cout << "pt = " << pt.get() << endl; 34 35 pt->print(); 36 37 cout << endl; 38 39 auto_ptr<Test> pt1(pt); // pt 转移了对堆空间的控制权,指向 NULL; 40 41 cout << "pt = " << pt.get() << endl; 42 cout << "pt1 = " << pt1.get() << endl; 43 44 pt1->print(); 45 46 return 0; 47 }
2,输出结果:
1 Hello, D.T.Software. 2 pt = 0x877c008 3 I'm D.T.Software. 4 5 pt = 0 6 pt1 = 0x877c008 7 I'm D.T.Software. 8 Goodbye, D.T.Software.
5,STL 中的其它智能指针:
1,shared_ptr:
1,带有引用计数机制,支持多个指针对象指向同一片内存;
2,weak_ptr:
1,配合 shared_ptr 而引入的一种智能指针;
3,unique_ptr:
1,一个指针对象指向一片内存空间,不能拷贝构造和赋值;
2,auto_ptr 的进化版,不能进行控制权的转移,通过不能拷贝构造和赋值实现;
6,Qt 中的智能指针:
1,QPointer:
1,当其指向的对象被销毁(释放)时,它会被自动置空;
1,可以使用多个 QPointer 智能指针指向同一个对象,当这个对象被销毁的时候,所有的智能指针对象都变为空,这可以避免多次释放和野指针的问题,非常好;
2,析构时不会自动销毁所指向的对象;
1,也就是当 QPointer 对象生命周期完结的时候,不会自动销毁堆空间中的对象,需要手动销毁;
2,这个是它的缺点,以后编程要注意这一点和其它智能指针不同;
2,QSharedPointer(和 STL 中的同名指针类模板相似):
1,引用计数型智能指针;
1,引用计数的对象是堆空间申请的对象;
2,可以被自动第拷贝和赋值;
3,当引用计数为 0 时才删除指向的对象;
1,这个智能指针对象生命周期结束后,引用计数减一;
3,Qt 还要提供自己的智能指针是和它的架构开发思想相关,因为 Qt 有自己的内存管理思想,但是这些思想并没有在 STL 中实现,所以说为了将这种内存管理思想贯彻到 Qt 中的方方面面,所以 Qt 才开发了自己的智能指针类模板,最常用和最具代表性的就是上面两类;
7,Qt 中的智能指针编程实验:
1,main.cpp 文件:
1 #include <QPointer> 2 #include <QSharedPointer> 3 #include <QDebug> 4 5 class Test : public QObject // Qt 开发中都要将类继承自 QObject; 6 { 7 QString m_name; 8 public: 9 Test(const char* name) 10 { 11 qDebug() << "Hello, " << name << "."; 12 13 m_name = name; 14 } 15 16 void print() 17 { 18 qDebug() << "I'm " << m_name << "."; 19 } 20 21 ~Test() 22 { 23 qDebug() << "Goodbye, " << m_name << "."; 24 } 25 }; 26 27 int main() 28 { 29 QPointer<Test> pt(new Test("D.T.Software")); 30 QPointer<Test> pt1(pt); 31 QPointer<Test> pt2(pt); 32 33 pt->print(); 34 pt1->print(); 35 pt2->print(); 36 37 delete pt; // 手工删除,这里只用删除一次就可,上述三个指针都指向NULL; 38 39 qDebug() << "pt = " << pt; // QObject(0x0) 40 qDebug() << "pt1 = " << pt1; // QObject(0x0) 41 qDebug() << "pt2 = " << pt2; // QObject(0x0) 42 43 qDebug() << endl; 44 45 QSharedPointer<Test> spt(new Test("Delphi Tang")); // 引用计数是相对于 Text("Delphi Tang") 对象而言; 46 QSharedPointer<Test> spt1(spt); 47 QSharedPointer<Test> spt2(spt); 48 49 spt->print(); 50 spt1->print(); 51 spt2->print(); 52 53 return 0; 54 }
2,输出结果:
1 Hello, D.T.Software. 2 I'm "D.T.Software". 3 I'm "D.T.Software". 4 I'm "D.T.Software". 5 Goodbye, "D.T.Software". 6 pt = QObject(0x0) 7 pt1 = QObject(0x0) 8 pt2 = QObject(0x0) 9 10 Hello, D.T.Software. 11 I'm "D.T.Software". 12 I'm "D.T.Software". 13 I'm "D.T.Software". 14 Goodbye, "D.T.Software".
8,Qt 中的其它智能指针:
1,QweakPointer;
2,QScopedPointer;
3,QScopedArrayPointer;
4,QSharedDataPointer;
5,QExplicitlySharedDataPointer;
9,创建智能指针类模板编程实验:
1,SmartPointer.h 文件:
1 #ifndef _SMARTPOINTER_H_ 2 #define _SMARTPOINTER_H_ 3 4 template 5 < typename T > 6 class SmartPointer 7 { 8 T* mp; 9 public: 10 SmartPointer(T* p = NULL) 11 { 12 mp = p; 13 } 14 15 SmartPointer(const SmartPointer<T>& obj) 16 { 17 mp = obj.mp; 18 const_cast<SmartPointer<T>&>(obj).mp = NULL; 19 } 20 21 SmartPointer<T>& operator = (const SmartPointer<T>& obj) 22 { 23 if( this != &obj ) 24 { 25 delete mp; 26 mp = obj.mp; 27 const_cast<SmartPointer<T>&>(obj).mp = NULL; 28 } 29 30 return *this; 31 } 32 33 T* operator -> () 34 { 35 return mp; 36 } 37 38 T& operator * () 39 { 40 return *mp; 41 } 42 43 bool isNull() 44 { 45 return (mp == NULL); 46 } 47 48 T* get() 49 { 50 return mp; 51 } 52 53 ~SmartPointer() 54 { 55 delete mp; 56 } 57 }; 58 59 #endif
2,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 #include "SmartPointer.h" 4 5 using namespace std; 6 7 class Test 8 { 9 string m_name; 10 public: 11 Test(const char* name) 12 { 13 cout << "Hello, " << name << "." << endl; 14 15 m_name = name; 16 } 17 18 void print() 19 { 20 cout << "I'm " << m_name << "." << endl; 21 } 22 23 ~Test() 24 { 25 cout << "Goodbye, " << m_name << "." << endl; 26 } 27 }; 28 29 int main() 30 { 31 SmartPointer<Test> pt(new Test("D.T.Software")); 32 33 cout << "pt = " << pt.get() << endl; 34 35 pt->print(); 36 37 cout << endl; 38 39 SmartPointer<Test> pt1(pt); 40 41 cout << "pt = " << pt.get() << endl; 42 cout << "pt1 = " << pt1.get() << endl; 43 44 pt1->print(); 45 46 return 0; 47 }
3,输出结果:
1 Hello, D.T.Software. 2 pt = 0x9881008 3 I'm D.T.Software. 4 5 pt = 0 6 pt1 = 0x9881008 7 I'm D.T.Software. 8 Goodbye, D.T.Software.
4,参照了 auto_ptr 的设计,也会发生堆空间控制权的转移,发生在拷贝构造函数和符赋值操作符中;
10,小结:
1,智能指针 C++ 中自动内存管理的主要手段;
2,智能指针在各种平台上都有不同的表现形式;
1,以类模板方式出现;
3,智能指针能够尽可能的避开内存相关的问题;
1,内存泄漏;
2,多次释放;
4,STL 和 Qt 中都提供了对智能指针的支持;