内存泄漏
-动态申请堆空间,用完后不归还
-c++语言中没有垃圾回收机制
-指针无法控制所指堆空间的生命周期
代码练兵场:
#ifndef SMARTPOINTER_H #define SMARTPOINTER_H namespace DTLib { template<typename T> class SmartPointer { public: SmartPointer(T *p=nullptr) { m_pointer=p; } SmartPointer(const SmartPointer<T>& obj) { m_pointer=obj.m_pointer; const_cast<SmartPointer<T>&>(obj).m_pointer=nullptr; } SmartPointer<T>& operator =(const SmartPointer<T>& obj) { if(this!=&obj) { delete m_pointer;//一定要先释放之前指向的空间,虽然可能delete一个null指针让我们觉得有点怪异,比如默认初始化sp,然后把p赋值给sp,此时delete的是null,但是程序是没有害处的、要是想要完全合乎new和delete配对,可以在这个delete前加一个if判断,如果非NULL,就delete m_pointer=obj.m_pointer; const_cast<SmartPointer<T>&>(obj).m_pointer=nullptr; } return *this; } T *operator->() { return m_pointer; } T &operator*() { return *m_pointer; } bool isNull() { return (m_pointer==nullptr); } T *get() { return m_pointer; } ~SmartPointer() { delete m_pointer; } protected: T *m_pointer; }; } #endif // SMARTPOINTER_H
main.cpp:
#include <iostream> #include "smartpointer.h" using namespace std; using namespace DTLib; class Test { public: Test() { cout<<" Test()"<<endl; } ~Test() { cout<<" ~Test()"<<endl; } }; int main() { SmartPointer<Test> p= new Test(); SmartPointer<Test> sp=p; // sp=p; //sp++; cout<<p.isNull()<<endl; cout<<sp.isNull()<<endl; return 0; }
输出:
代码知识点解释:
const_cast<SmartPointer<T>&>(obj).m_pointer=nullptr;,在拷贝构造函数中,obj是const的,内容不允许修改,但是我们的智能指针设计需求第二步,开辟的堆空间,只能有一个指针标识,所以我想去掉obj类中的指针成员的指向,使用强制类型转化,去掉obj类的const属性,注意obj是我们要去const化的,而不是obj.m_pointer。同样的道理,我们需要重载赋值运算符,在不是自赋值的情况下,满足重载赋值运算符的if条件(针对上面的代码而言),释放this的m_pointer指向的内存,把obj的指针赋值给this的m_pointer,再把obj的m_pointer指针置成null,这样还是为了只给一个指针标识。然后重载了->和解引用*操作符。在main.cpp中,我们创建了一个Test类,用智能指针指向这个new出来的类,再把p指针用了初始化sp(将调用拷贝构造函数),此时,首先打印Test的无参构造函数,然后p初始化了sp,故p的m_pointer应该被置成了null,所以isNull函数返回1,但是sp此时接管Test类的内存,所以sp的isNull返回0,非空。最后Test类析构,智能指针指向的内存也会因为调用了自己的析构函数释放内存。在我们实现的智能指针中,是不运行执行指针和比较的,执行++这种操作是没有定义的,符合之前我们提到的智能指针三个要求。c++11中,建议用nullptr代替NULL。
NOTE:
智能指针用来指向堆空间中的单个对象或者变量。