auto_ptr 源码

最近开了auto_ptr,看了它的很多的应用与规则,有些迷惑的地方,故拿来它的源码研究一翻:

Code:
  1.  template<typename _Tp1>   
  2.    struct auto_ptr_ref   
  3.    {   
  4.      _Tp1* _M_ptr;   
  5.         
  6.      explicit  
  7.      auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }   
  8.    };   
  9.  template<typename _Tp>   
  10.    class auto_ptr   
  11.    {   
  12.    private:   
  13.      _Tp* _M_ptr;   
  14.         
  15.    public:   
  16.      /// The pointed-to type.   
  17.      typedef _Tp element_type;   
  18.         
  19.      explicit  
  20.      auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }   
  21.      auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }   
  22.      template<typename _Tp1>   
  23.        auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }   
  24.      auto_ptr&   
  25.      operator=(auto_ptr& __a) throw()   
  26.      {   
  27. reset(__a.release());   
  28. return *this;   
  29.      }   
  30.      template<typename _Tp1>   
  31.        auto_ptr&   
  32.        operator=(auto_ptr<_Tp1>& __a) throw()   
  33.        {   
  34.   reset(__a.release());   
  35.   return *this;   
  36. }   
  37.      ~auto_ptr() { delete _M_ptr; }   
  38.      element_type&   
  39.      operator*() const throw()    
  40.      {   
  41. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);   
  42. return *_M_ptr;    
  43.      }   
  44.      element_type*   
  45.      operator->() const throw()    
  46.      {   
  47. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);   
  48. return _M_ptr;    
  49.      }   
  50.      element_type*   
  51.      get() const throw() { return _M_ptr; }   
  52.      element_type*   
  53.      release() throw()   
  54.      {   
  55. element_type* __tmp = _M_ptr;   
  56. _M_ptr = 0;   
  57. return __tmp;   
  58.      }   
  59.      void  
  60.      reset(element_type* __p = 0) throw()   
  61.      {   
  62. if (__p != _M_ptr)   
  63.   {   
  64.     delete _M_ptr;   
  65.     _M_ptr = __p;   
  66.   }   
  67.      }   
  68.      auto_ptr(auto_ptr_ref<element_type> __ref) throw()   
  69.      : _M_ptr(__ref._M_ptr) { }   
  70.         
  71.      auto_ptr&   
  72.      operator=(auto_ptr_ref<element_type> __ref) throw()   
  73.      {   
  74. if (__ref._M_ptr != this->get())   
  75.   {   
  76.     delete _M_ptr;   
  77.     _M_ptr = __ref._M_ptr;   
  78.   }   
  79. return *this;   
  80.      }   
  81.         
  82.      template<typename _Tp1>   
  83.        operator auto_ptr_ref<_Tp1>() throw()   
  84.        { return auto_ptr_ref<_Tp1>(this->release()); }   
  85.   
  86.      template<typename _Tp1>   
  87.        operator auto_ptr<_Tp1>() throw()   
  88.        { return auto_ptr<_Tp1>(this->release()); }   
  89.  };   

1 首先看一下开始的哪个小结构体

Code:
  1. template<typename _Tp1>   
  2.   struct auto_ptr_ref   
  3.   {   
  4.     _Tp1* _M_ptr;   
  5.        
  6.     explicit  
  7.     auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }   
  8.   };  

这个结构体成员中仅有一个指针和一个显示构造函数。仅从表面上来看,它封装了一个指针类型,从源码来看,它提供了一种转换,即:从这种结构体类型到auto_ptr的转换。

2 类型定义

Code:
  1. typedef _Tp element_type;  

为auto_ptr定一个成员类型。我们可以如下方法使用这种类型:

Code:
  1. #include <iostream>   
  2. #include <memory>   
  3. #include <typeinfo>   
  4. #include <string>   
  5. using namespace std;   
  6. int main()   
  7. {   
  8.     auto_ptr<int>::element_type p = 6;   
  9.     cout << p << endl;   
  10.     cout << typeid(p).name() << endl;   
  11.     system("pause");   
  12.     return 0;   
  13. }  

在程序中auto_ptr<int>::element_type 其实就是int类型。我们在程序中也验证了。

3 构造函数

Code:
  1. explicit  
  2.      auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }  

构造函数被定义为explicit,那么我们在定义对象的时候的存在隐式转换的定义就无法通过编译了。如:

Code:
  1. auto_ptr<int> p = new int(6); //error   
  2. auto_ptr<int> p (new int(6)); // ok;  

4 拷贝构造函数

Code:
  1. auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }   
  2.  template<typename _Tp1>   
  3.    auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }  

拷贝构造函数被定义了两个版本,一个模板版本,一个非模板版本。为什么这样做呢?这不禁令我想起了模板的一个性质,即,当一个函数同时存在模板版本和非模板版本的时候,在函数进行调用的时候,编译器首先拿实参和非模板版本来进行比较,如果匹配就优先调用非模板版本。而不去再实例化一个版本。只有类型和非模板版本的参数类型不完全匹配或是不匹配的时候才去实例化一个新版本。

这里提供一个模板版本的目的是为了能够允许类型自动转换从而构造处合适的auto_ptr。例如:可以根据一个派生类对象构造出一个基类对像的auto_ptr。

4 赋值函数

Code:
  1. auto_ptr&   
  2.      operator=(auto_ptr& __a) throw()   
  3.      {   
  4. reset(__a.release());   
  5. return *this;   
  6.      }   
  7.      template<typename _Tp1>   
  8.        auto_ptr&   
  9.        operator=(auto_ptr<_Tp1>& __a) throw()   
  10.        {   
  11.   reset(__a.release());   
  12.   return *this;   
  13. }  

这个函数同样也有两个版本,其意义和拷贝构造函数的相同。由于构造函数被声明成为explicit。故这样的行为也无法通过编译:

Code:
  1. auto_ptr<int> p (new int(5));   
  2. auto_ptr<int> q;   
  3. q = p; // ok.   
  4. q = new int (6); //error   
  5. q = auto_ptr<int>(new int(6)); // ok;  

5 析构函数

Code:
  1. ~auto_ptr() { delete _M_ptr; }  

析构函数简单,仅仅释放空间就ok了。

6 操作符重载

Code:
  1.      element_type&   
  2.      operator*() const throw()    
  3.      {   
  4. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);   
  5. return *_M_ptr;    
  6.      }   
  7.      element_type*   
  8.      operator->() const throw()    
  9.      {   
  10. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);   
  11. return _M_ptr;    
  12.      }  

这里重载了两个操作符,一个‘*’ 一个‘->’。这里面使用了断言。我猜测它_GLIBCXX_DEBUG_ASSERT就是assert。其实这样个函数的目的一个是为了得到指针所指的内容,一个是得到指针。

7 三个小函数

Code:
  1. element_type*   
  2.      get() const throw() { return _M_ptr; }   
  3.      element_type*   
  4.      release() throw()   
  5.      {   
  6. element_type* __tmp = _M_ptr;   
  7. _M_ptr = 0;   
  8. return __tmp;   
  9.      }   
  10.      void  
  11.      reset(element_type* __p = 0) throw()   
  12.      {   
  13. if (__p != _M_ptr)   
  14.   {   
  15.     delete _M_ptr;   
  16.     _M_ptr = __p;   
  17.   }   
  18.      }  

get()函数就是为了获得封装的指针。release()函数其实也是一个封装操作,他这里干了两件事,一个是返回对象封装的指针,然后把该指针赋0.它的目的是释放现在的指针,令它指向0,并传递指针的地址。reset()函数是用来设置指针。首先判断当前指针是否有值,若有值释放之,并赋值新值。

8 和auto_ptr_ref有关的函数

Code:
  1. auto_ptr(auto_ptr_ref<element_type> __ref) throw()   
  2.      : _M_ptr(__ref._M_ptr) { }   
  3.         
  4.      auto_ptr&   
  5.      operator=(auto_ptr_ref<element_type> __ref) throw()   
  6.      {   
  7. if (__ref._M_ptr != this->get())   
  8.   {   
  9.     delete _M_ptr;   
  10.     _M_ptr = __ref._M_ptr;   
  11.   }   
  12. return *this;   
  13.      }   
  14.         
  15.      template<typename _Tp1>   
  16.        operator auto_ptr_ref<_Tp1>() throw()   
  17.        { return auto_ptr_ref<_Tp1>(this->release()); }   
  18.   
  19.      template<typename _Tp1>   
  20.        operator auto_ptr<_Tp1>() throw()   
  21.        { return auto_ptr<_Tp1>(this->release()); }  

首先是一个构造函数,然后是赋值函数,然后便是类型转换符。

构造函数和赋值函数提供了auto_ptr_ref类型到auto_ptr类型的转换。两个转换函数同样提供了auto_ptr_ref和auto_ptr之间的相互转换。

至此整个auto_ptr的源码就看完了,但是更多的东西还需在使用中才能有更深的体会。。

现在我们看auto_ptr的使用例子:

 拥有权的转移

Code:
  1. #include <iostream>    
  2. #include <memory>   
  3. using namespace std;   
  4. template <typename T>   
  5. ostream& operator << (ostream& strm,const auto_ptr<T>&p)   
  6. {   
  7.     if (p.get() == NULL)   
  8.     {   
  9.         strm << "NULL";   
  10.     }   
  11.     else  
  12.     {   
  13.         strm << *p;   
  14.     }   
  15.     return strm;   
  16. }   
  17. int main()       
  18. {       
  19.     auto_ptr<int> p(new int(42));   
  20.     auto_ptr<int> q;   
  21.     cout << "after initialization: " << endl;   
  22.     cout << " p: " << p << endl;   
  23.     cout << " q: " << q << endl;   
  24.     q = p;   
  25.     cout << "after assigning auto pointers: " << endl;   
  26.     cout << " p: " << p << endl;   
  27.     cout << " q: " << q << endl;   
  28.     *q += 13;   
  29.     p = q;   
  30.     cout << "after change and reassignment: " << endl;   
  31.     cout << " p: " << p << endl;   
  32.     cout << " q: " << q << endl;   
  33.     system("pause");   
  34.     return 0;       
  35. }   

const auto_ptr<T> 拥有权不能转移,但可以改变它的值。

Code:
  1. #include <iostream>    
  2. #include <memory>   
  3. using namespace std;   
  4. template <typename T>   
  5. ostream& operator << (ostream& strm,const auto_ptr<T>&p)   
  6. {   
  7.     if (p.get() == NULL)   
  8.     {   
  9.         strm << "NULL";   
  10.     }   
  11.     else  
  12.     {   
  13.         strm << *p;   
  14.     }   
  15.     return strm;   
  16. }   
  17. int main()       
  18. {       
  19.     auto_ptr<int> p(new int(42));   
  20.     const auto_ptr<int> t(new int(5));   
  21.     cout << t << endl;   
  22.     *t = 6; // ok.   
  23.     cout << t << endl;   
  24.     p = t;///error.   
  25.     system("pause");   
  26.     return 0;       
  27. }   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C标准库中的智能指针主要有4个,分别是auto_ptr、unique_ptr、shared_ptr和weak_ptrauto_ptr是C++98标准中最早提出的智能指针,但在C++11之后不建议使用。了解auto_ptr源码可以帮助我们更好地理解智能指针的原理和使用。智能指针的实现涉及模板类、函数对象、操作符重载以及其他C++技术的综合运用,它解决了C程序员在内存管理方面的困扰。想要更清晰地了解智能指针的内部原理以及更好地使用它,看一下源码是很有必要的。 智能指针还提供了一个get()函数,用于返回智能指针管理的对象的普通指针。这个函数的存在是为了向不能使用智能指针的代码传递普通指针。例如,我们可以使用std::shared_ptr<int> p1 = std::make_shared<int>(1024)创建一个智能指针,然后通过p1.get()获取其所管理对象的普通指针,即int* p2 = p1.get()。 智能指针是C++标准库中的一个重要组成部分。它帮助C++程序员解决了内存开辟和释放的问题,使得程序员不再像C语言一样担心内存泄漏的问题。使用智能指针需要包含头文件#include <memory>。 在使用智能指针时,应避免混用普通指针和智能指针。例如,在一个函数中,我们应该避免在参数中使用智能指针,然后又将其传递给接受普通指针的函数。这样的混用可能导致内存管理问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值