面试的时候,我们经常会被问到如何自己动手实现智能指针auto_ptr.今天我就一边参考STL库中的源代码,一边将auto_ptr的实现敲一遍。
auto_ptr归根到底是一个模版类,那么这个类要实现哪些功能呢?如下:
/*
一个智能指针应该有以下操作:
1.Auto_ptr<T> ap; //创建名为ap的为绑定Auto_ptr对象
2.Auto_ptr<T> ap(p); //创建 ap 的Auto_ptr对象,ap用友指针 p 指向的对象。该构造函数为explicit
3.Auto_ptr<T> ap1(ap2) //创建名为ap1的Auto_ptr对象,ap1保存原来存在ap2中的指针。将所有权转给ap1,ap2成为未绑定的Auto_ptr对象
4.ap1 = ap2 //将所有权从ap2转给ap1。删除ap1指向的对象并且使ap1指向ap2指向的对象,使ap2成为未绑定的
5.~ap //析构函数。删除ap指向的对象
6.*ap //返回对ap所绑定对象的引用
7.ap-> //返回ap保存的指针
8.ap.reset(p) //如果ap与p的值不同,则删除ap指向的独享并且将ap绑定到p
9.ap.release() //返回ap所保存的指针并且是ap成为未绑定的
10.ap.get() //返回ap保存的指针
*/
具体代码如下:
1 template<class T> 2 class Auto_ptr { 3 private: 4 T *ptr; //真正的指针值 5 mutable bool owns; //是否拥有该指针 6 public: 7 //不可以隐式转化的构造函数 8 explicit Auto_ptr(T *p = 0):ptr(p),owns((bool)p){} //不能隐式转化,例如Auto_ptr<int> Ap = new int(1024) //error 9 //复制构造函数 10 //Auto_ptr(const Auto_ptr& a):ptr(a.ptr),owns(a.owns){ a.owns = 0;} 11 //泛化版的复制构造函数 12 template <class U> 13 Auto_ptr(const Auto_ptr<U>& a):ptr(a.ptr),owns(a.owns){ a.owns = 0;} 14 15 //重载赋值操作符 16 Auto_ptr& operator=(const Auto_ptr& a) 17 { 18 if(&a != this) //防止自身赋值 19 { 20 if(owns) 21 delete ptr; 22 owns = a.owns; 23 ptr = a.ptr; 24 a.owns = 0; 25 } 26 } 27 //泛化版的重载赋值操作符 28 template<class U> 29 Auto_ptr& operator=(Auto_ptr<U>& a) 30 { 31 if (&a != this) 32 { 33 if(owns) 34 delete ptr; 35 owns = a.owns; 36 ptr = a.ptr; 37 a.owns = false; 38 } 39 return *this; 40 } 41 T& operator *() const {return *ptr;} 42 T* operator ->() const {return ptr;} 43 T* get() const { return ptr;} 44 void reset(T *p = 0) 45 { 46 if(owns) 47 { 48 if(ptr != p) //如果p 和 ptr的值不同 49 { 50 delete ptr; //删除原来指向的对象 51 } //else付过相同肯定不能删除啊 52 } 53 ptr = p; //这里赋值时安全的,机试ptr和p原来相等 54 } 55 T* release() const{ owns = false;return ptr;} 56 ~Auto_ptr(){if(owns) {cout << "析构!"<< endl;delete ptr;}} 57 };
测试代码如下:
1 #include<iostream> 2 3 using namespace std; 4 5 int main() 6 { 7 Auto_ptr<int> Ap; 8 Auto_ptr<int> Ap1(new int(1024)); 9 //Auto_ptr<int> Ap2 = new int(1024); //error 10 //if(Ap == NULL) //error 11 if(Ap.get() == NULL) 12 { 13 cout << "Ap is NULL!" << endl; 14 } 15 cout << "Before = Ap1 value is:" << Ap1.get() << endl; 16 Auto_ptr<int> Ap3 ; 17 Ap3 = Ap1; 18 cout << "After = Ap1 value is:" << Ap1.get() << endl; 19 int *p = Ap3.release(); 20 cout << "Ap3 value is:" << Ap3.get() << endl; 21 Ap3.reset(new int(12)); 22 cout << "Ap3 value is:" << Ap3.get() << endl; 23 return 0; 24 }
测试的结果:
由上图我们可以看到Ap1在 赋值=之前和之后都指向的地址都是00620FB8,说明赋值并没有改变智能指针的指向,只是将拥有的标志owns改变了。通过reset函数可以重新绑定智能指针!