第一次使用auto_ptr的时候感觉很好用,但是对内部原理根本不懂,心里不知道这东西到底是个什么东东,总是感觉这东东比较陌生。今天有时间来简单实现一下该类模版auto_ptr,实现了该模版类的主要功能,可以让大家了解一下这个东东内部到底是个什么情况。
栈对象和堆对象的区别:
首先,看一下两种类对象的区别,一个是在栈上分配空间,另一个是在堆上分配空间。
如果看到这里,你不清楚堆和栈的区别。那我也不解释了,自行Google..(如果你想baidu也不拦你)
1、先测试栈上分配的对象
#include <iostream> #include <memory> using namespace std; /**************************************** * 类名称:A(用于测试的类) ****************************************/ class A { public: A(int num):a(num){cout << "A(int num)" << endl;} A(){cout << "A()" << endl;} ~A(){cout << "~A()" << endl;} void func(){ cout << "A.fun()" << endl; } private: int a; }; /**************************************** * 主测试函数main ****************************************/ int main() { A a1; a1.func(); //A * pa = new A(); //pa->func(); return 0; }
程序输出为:
A() A.fun() ~A()
从输出结果可以看出,在栈上分配的对象在离开作用域的时候会自动调用析构函数,不用手动释放。
2、再测试堆上分配的对象
将上面的main函数改为下面:
/**************************************** * 主测试函数main ****************************************/ int main() { //A a1; //a1.func(); A * pa = new A(); pa->func(); return 0; }
程序输出为:
A() A.fun()
从输出结果可以看出,在堆上分配的对象在离开作用域的时候不会自动调用析构函数,需要手动释放。
下面是添加手动释放对象的语句:
/**************************************** * 主测试函数main ****************************************/ int main() { //A a1; //a1.func(); A * pa = new A(); pa->func(); delete pa; return 0; }
下面是改了之后的程序输出:
A() A.fun() ~A()
为什么需要智能指针?
从上面的例子可以看出,对于在堆上分配的对象的释放是一件比较麻烦的事情,如果忘了手动释放,那就会造成内存的泄漏。如果全部收到释放,那么又给程序员带来很大的麻烦。
那么就想啊,有什么办法可以像栈对象那样操作堆对象。栈对象是在栈内存空间的对象,当对象超过作用域的时候会自动释放。那么我们可以让栈内存空间上的一个指针对象专门来管理堆对象,当指针对象离开作用域的时候肯定会调用自身的析构函数,那么我们在指针对象的析构函数中对它管理的堆对象内存空间进行释放。
智能指针auto_ptr简单应用实例:
#include <iostream> #include <memory> using namespace std; /**************************************** * 类名称:A(用于测试的类) ****************************************/ class A { public: A(int num):a(num){cout << "A(int num)" << endl;} A(){cout << "A()" << endl;} ~A(){cout << "~A()" << endl;} void func(){ cout << "A.fun()" << endl; } private: int a; }; /**************************************** * 主测试函数main ****************************************/ int main() { //使用智能指针模版类auto_ptr //new A等价于new A(),但是如果有括号的话,可以调用带参的构造函数,如new A(10); auto_ptr<A> ptr(new A); ptr->func(); (*ptr).func(); return 0; }
程序输出为:
A() A.fun() A.fun() ~A()
在上面的例子中可以看出,auto_ptr是一个模版类,我们在这里定义了一个管理类A对象的一个指针对象ptr,该指针对象ptr可以使用运算符->和*,所以在类auto_ptr中重载了运算符->和*。
在上面例子中的指针对象ptr是栈对象,在离开作用域的时候会自动释放,然后会自动调用析构函数,在它的析构函数中会释放它指向的堆对象,从而达到了智能指针的效果。
重写智能指针模版类SmartPointer:
/**************************************** * 类名称:Smart智能指针模版类 ****************************************/ template<typename T> class SmartPointer { public: //构造函数 SmartPointer(T * p = NULL):ptr(p){ } //析构函数 ~SmartPointer(){ if(ptr != NULL) delete ptr; } //重载->运算符 T * operator->(){ return ptr; } //重载*运算符 T & operator*(){ return *ptr; } private: T * ptr; };
在程序中可以看出,该模版类重载了运算符->和*,并实现了管理堆对象的功能。
下面是测试智能指针模版类SmartPointer:
/************************************************************************* > File Name: smartPointerTemplate.cpp > Author: > Mail: > Created Time: 2016年05月10日 星期二 19时26分14秒 ************************************************************************/ #include <iostream> using namespace std; /**************************************** * 类名称:A(用于测试的类) ****************************************/ class A { public: A(int num):a(num){cout << "A(int num)" << endl;} A(){cout << "A()" << endl;} ~A(){cout << "~A()" << endl;} void func(){ cout << "A::fun()" << endl; } private: int a; }; /**************************************** * 类名称:B(用于测试的类) ****************************************/ class B { public: B(){cout << "B()" << endl;} ~B(){cout << "~B()" << endl;} void func(){ cout << "B::func()" << endl; } }; /**************************************** * 类名称:Smart智能指针模版类 ****************************************/ template<typename T> class SmartPointer { public: //构造函数 SmartPointer(T * p = NULL):ptr(p){ } //析构函数 ~SmartPointer(){ if(ptr != NULL) delete ptr; } //重载->运算符 T * operator->(){ return ptr; } //重载*运算符 T & operator*(){ return *ptr; } private: T * ptr; }; /**************************************** * 主测试函数main ****************************************/ int main() { SmartPointer<A> smt(new A()); smt->func(); (*smt).func(); SmartPointer<B> smtB(new B()); smtB->func(); (*smtB).func(); return 0; }
下面是程序的输出结果:
A() A::fun() A::fun() B() B::func() B::func() ~B() ~A()
从输出结果可以看出该模版类智能指针也实现了管理堆对象的功能。