zoukankan      html  css  js  c++  java
  • C++——几种简单的智能指针

    最简单的智能指针就是将指针封装在类里,同时将该类的复制与赋值禁用,也就是使该类失去值语义。

    在boost中,这种智能指针也叫做scoped_ptr

    实现代码如下:

     1 #ifndef SMART_PTR_H
     2 #define SMART_PTR_H
     3 #include <iostream>
     4 
     5 
     6 template <typename T>
     7 class SmartPtr
     8 {
     9 public:
    10     typedef T          value_type;
    11     typedef T*        pointer;
    12     typedef T&        reference;
    13 
    14     SmartPtr(T *ptr = NULL)
    15         :_ptr(ptr)
    16     { }
    17 
    18     ~SmartPtr() { delete _ptr; }
    19 
    20     reference operator* () const throw()
    21     { return *_ptr; }
    22 
    23     pointer operator-> () const throw()
    24     { return _ptr; }
    25     
    26 private:
    27     SmartPtr(const SmartPtr &);
    28     void operator=(const SmartPtr &);
    29 
    30     pointer _ptr;
    31 };
    32 
    33 #endif  /*SMART_PTR_H*/
    View Code

    相对于这种最简单的智能指针,我们还可以实现一种具有复制与赋值功能的智能指针——auto_ptr。

    实现代码如下:

     1 #ifndef AUTO_PTR_H
     2 #define AUTO_PTR_H
     3 #include <iostream>
     4 
     5 template <typename T>
     6 class AutoPtr
     7 {
     8 public:
     9     typedef T     value_type;
    10     typedef T*    pointer;
    11     typedef T&    reference;
    12 
    13 
    14     AutoPtr(T *ptr = NULL);
    15     AutoPtr(AutoPtr &other);
    16     ~AutoPtr();
    17     AutoPtr &operator= (AutoPtr &other) throw();
    18 
    19     reference operator*() const throw()
    20     { return *_ptr; }
    21 
    22     pointer operator->() const throw()
    23     { return _ptr; }
    24 
    25     void reset(T *ptr = NULL) throw()
    26     {
    27         if(_ptr != ptr)
    28         {
    29             delete _ptr;
    30             _ptr = ptr;
    31         }
    32     }
    33 
    34     pointer release() throw()
    35     {
    36         pointer tmp(_ptr);
    37         _ptr = NULL;
    38         return tmp;
    39     }
    40 
    41     operator bool() throw() { return _ptr != NULL; }
    42 
    43 private:
    44     value_type *_ptr;
    45 };
    46 
    47 
    48 template <typename T>
    49 AutoPtr<T>::AutoPtr(T *ptr)
    50     :_ptr(ptr)
    51 {
    52 
    53 }
    54 
    55 template <typename T>
    56 AutoPtr<T>::AutoPtr(AutoPtr<T> &other)
    57     :_ptr(other._ptr)
    58 {
    59     other._ptr = NULL;
    60 }
    61 
    62 template <typename T>
    63 AutoPtr<T>::~AutoPtr()
    64 {
    65     delete _ptr;
    66 }
    67 
    68 template <typename T>
    69 AutoPtr<T> &AutoPtr<T>::operator= (AutoPtr<T> &other) throw()
    70 {
    71     reset(other.release());
    72 
    73     return *this;
    74 }
    75 #endif  /*AUTO_PTR_H*/
    View Code

    在使用AutoPtr时,我们需要注意:

      1.AutoPtr的复制与赋值会引发控制权的转移,这是一种转移语义。

      2.不要使用AutoPtr,尤其是与容器结合。

      3.在AutoPtr中,我们提供了一种转化,将该类可转化为bool型。

    在C++11中,还有一种unique_ptr,该种智能指针也禁用了复制和赋值功能,但是它提供了移动构造能力和移动赋值 

    unique_ptr可以取代scoped_ptr,它保留了scoped_ptr的全部能力,同时提供了移动构造使得它可以放入容器中,没有带来额外的缺点。

    unique_ptr简单实现代码如下:

     1 #ifndef UNIQUE_PTR_H
     2 #define UNIQUE_PTR_H
     3 
     4 #include <algorithm>
     5 #include <iostream>
     6 
     7 template <typename T>
     8 class UniquePtr
     9 {
    10 public:
    11     typedef T     value_type;
    12     typedef T*    pointer;
    13     typedef T&    reference;
    14 
    15     explicit UniquePtr(T *ptr = NULL) throw()
    16         :_ptr(ptr)
    17     {
    18 
    19     }
    20     UniquePtr(UniquePtr &&s) throw()
    21         :_ptr(s._ptr)
    22     {
    23         s._ptr = NULL;
    24     }
    25     UniquePtr &operator= (UniquePtr &&s) throw()
    26     {
    27         if(this != &s)
    28         {
    29             delete _ptr;
    30             _ptr = s._ptr;
    31             s._ptr = NULL;
    32         }
    33 
    34         return *this;
    35     }
    36     ~UniquePtr() throw()
    37     {
    38         delete _ptr;
    39     }
    40 
    41     reference operator* () const throw()
    42     { return *_ptr; }
    43 
    44     pointer operator-> () const throw()
    45     { return _ptr; }
    46 
    47     pointer get() const throw()
    48     { return _ptr; }
    49 
    50     pointer release() throw()
    51     {
    52         pointer tmp(_ptr);
    53         _ptr = NULL;
    54         return tmp;
    55     }
    56 
    57     void reset(T *ptr = NULL) throw()
    58     {
    59         if(_ptr != ptr)
    60         {
    61             delete _ptr;
    62             _ptr = ptr;
    63         }
    64     }
    65 
    66 
    67     void swap(UniquePtr &other)
    68     {
    69         std::swap(_ptr, other._ptr);
    70     }
    71 
    72 private:
    73     UniquePtr(const UniquePtr &);
    74     void operator= (const UniquePtr &);
    75 
    76     pointer _ptr;
    77 };
    78 
    79 
    80 
    81 
    82 
    83 #endif  /*UNIQUE_PTR_H*/
    View Code

    在C++11中,我们可以使用unique_ptr为中介,将不具备复制、赋值和移动能力的元素放入容器中。

    对于智能指针来说,比较常用的一种实现方法是使用引用计数,创建新的对象时,我们将计数器count初始化为1,每次复制该对象或将该对象赋值给其他对象时,计数器count加1,析构的时候将计数器减1,当计数器为0时,我们才真正删除该对象内的指针。

    具体实现代码如下:

     1 #ifndef COUNT_PTR_H
     2 #define COUNT_PTR_H
     3 #include <iostream>
     4 
     5 
     6 template <typename T>
     7 class CountPtr
     8 {
     9 public:
    10     typedef T                 value_type;
    11     typedef T*                pointer;
    12     typedef T&                reference;
    13 
    14 
    15     explicit CountPtr(T *p = NULL);
    16     CountPtr(const CountPtr<T> &other);
    17     ~CountPtr();
    18 
    19     CountPtr<T> &operator= (const CountPtr<T> &other);
    20     reference operator*() const throw() { return *_ptr; }
    21 
    22     pointer operator->() const throw() { return _ptr; }
    23 
    24     size_t count() const throw() { return *_count; }
    25 
    26     void swap(CountPtr<T> &other) throw()
    27     {
    28         std::swap(_ptr, other._ptr);
    29         std::swap(_count, other._count);
    30     }
    31 
    32     void reset(T *ptr = NULL) throw()
    33     {
    34         dispose();
    35 
    36         _ptr = ptr;
    37         _count = new size_t(1);
    38     }
    39 
    40 
    41     pointer get() const throw() { return _ptr; }
    42 
    43     bool unique() const throw() { return *_count == 1; }
    44 
    45     operator bool() { return _ptr != NULL; }
    46 private:
    47 
    48     void dispose()
    49     {
    50         if(-- *_count == 0)
    51         {
    52             delete _ptr;
    53             delete _count;
    54         }
    55     }
    56 
    57     T *_ptr;
    58     size_t *_count;
    59 
    60 };
    61 
    62 template <typename T>
    63 CountPtr<T>::CountPtr(T *p)
    64     :_ptr(p),
    65      _count(new size_t(1))
    66 {
    67 
    68 }
    69 
    70 template <typename T>
    71 CountPtr<T>::~CountPtr()
    72 {
    73     dispose();
    74 }
    75 
    76 template <typename T>
    77 CountPtr<T>::CountPtr(const CountPtr<T> &other)
    78     :_ptr(other._ptr),
    79      _count(other._count)
    80 {
    81     ++ (*_count);
    82 }
    83 
    84 template <typename T>
    85 CountPtr<T> &CountPtr<T>::operator= (const CountPtr<T> &other)
    86 {
    87     ++(*other._count);            //先++防止自身赋值失败
    88 
    89     dispose();
    90 
    91     _ptr = other._ptr;
    92     _count = other._count;
    93 
    94     return *this;
    95 }
    96 #endif  /*COUNT_PTR_H*/
    View Code

    在引用计数智能指针中,需要注意:
      1.计数器count采用指针,这样每个指针共享一个计数。

      2.析构时,仅将引用计数减1,只有当计数为0时,才释放资源。

      3.复制指针时,计数将加1.

      4.赋值时,可以先对other的计数加1,来避免处理自我赋值。

    使用引用计数指针,可以将失去值语义的对象放入容器中。

    在C++11中,提供了shared_ptr这种引用计数型的智能指针,但是需要注意:

      shared_ptr使用不当会造成内存泄露,原因可能是两个堆上的对象相互引用,所以引用计数始终为1,造成一个环状结构,找不到对象delete的时机。

    解决这种错误的方法是使用:weak_ptr.

    weak_ptr要与shared_ptr配合使用,它只指向对象地址,但是不参与引用计数,是一种弱引用

     下面给出一种简单的内存泄露处理示例:

     1 #include <iostream>
     2 #include <memory>
     3 using namespace std;
     4 
     5 class Parent;
     6 class Child;
     7 
     8 typedef shared_ptr<Parent> ParentPtr;
     9 typedef shared_ptr<Child> ChildPtr;
    10 
    11 class Parent
    12 {
    13 public:
    14     ~Parent() { cout << "~Parent" << endl; }
    15 
    16 
    17     ChildPtr _child;
    18 };
    19 
    20 class Child
    21 {
    22 public:
    23     Child(const ParentPtr &ptr)
    24         :_parent(ptr)
    25     {}
    26     ~Child() { cout << "~Child" << endl; }
    27 
    28     //ParentPtr _parent;
    29     std::weak_ptr<Parent> _parent;
    30 };
    31 
    32 int main(int argc, const char *argv[])
    33 {
    34     ParentPtr ptr1(new Parent);
    35     ChildPtr ptr2(new Child(ptr1));
    36     ptr1->_child = ptr2;
    37     ptr2->_parent = ptr1;
    38     return 0;
    39 }
    View Code

    在这里,我们将Child中的_parent指针设置为弱指针,当我们执行 ptr2->_parent = ptr1; 时,并没有将ptr1 中的计数加1,这是一种弱引用,当析构时,ptr1由于计数减 1 后计数为0,首先释放内存,这个时候,ptr1中的_child指针也被销毁,所以ptr2中的计数减1; 然后再析构ptr2时,将ptr2计数减 1 ,这时ptr2中的计数为0,释放内存。

  • 相关阅读:
    使用 Trello 管理自己与团队的工作
    Google译者工具包
    curl的速度为什么比file_get_contents快以及具体原因
    Mac使用秘钥登录Linux服务器
    curl抓取页面时遇到重定向的解决方法
    PHP cURL 超时设置 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT 的区别
    max函数比较字符串类型
    Dictionary 泛型类
    .NET Framework 概念概述
    认知Web服务器
  • 原文地址:https://www.cnblogs.com/gjn135120/p/4011641.html
Copyright © 2011-2022 走看看