zoukankan      html  css  js  c++  java
  • 第二十七课 再论智能指针(上)

    思考:

      使用智能指针替换单链表LinkLIst中的原生指针是否可行?

    将LinkList.h中的Node指针全部改成智能指针:

      1 #ifndef LINKLIST_H
      2 #define LINKLIST_H
      3 
      4 #include "List.h"
      5 #include "Exception.h"
      6 #include "SmartPointer.h"
      7 
      8 namespace DTLib
      9 {
     10 
     11 template < typename T >
     12 class LinkList : public List<T>
     13 {
     14 protected:
     15     struct Node : public Object
     16     {
     17         T value;
     18         SmartPointer<Node> next;
     19     };
     20 
     21     mutable struct : public Object
     22     {
     23         char reserved[sizeof(T)];
     24         SmartPointer<Node> next;
     25     }m_header;
     26 
     27     int m_length;
     28     int m_step;
     29     SmartPointer<Node> m_current;
     30 
     31     Node* position(int i) const    //  O(n)
     32     {
     33         //Node* ret = reinterpret_cast<Node*>(&m_header);
     34         SmartPointer<Node> ret = reinterpret_cast<Node*>(&m_header);
     35 
     36         for(int p = 0; p < i; p++)
     37         {
     38             ret = ret->next;
     39         }
     40 
     41         return ret.get();
     42     }
     43 
     44     virtual Node* create()
     45     {
     46         return new Node();
     47     }
     48 
     49     virtual void destroy(Node* pn)
     50     {
     51         delete pn;
     52     }
     53 
     54 public:
     55     LinkList()
     56     {
     57         m_header.next = NULL;
     58         m_length = 0;
     59         m_step = 1;
     60         m_current = NULL;
     61     }
     62 
     63     bool insert(const T& e)
     64     {
     65         return insert(m_length, e);
     66     }
     67 
     68     bool insert(int i, const T& e)   // O(n)
     69     {
     70         bool ret = ((0 <= i) && (i <= m_length));
     71 
     72         if( ret )
     73         {
     74             Node* node = create();
     75 
     76             if( node != NULL )
     77             {
     78                 Node* current = position(i);
     79 
     80                 node->value = e;
     81                 node->next = current->next;
     82                 current->next = node;
     83 
     84                 m_length++;
     85             }
     86             else
     87             {
     88                 THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
     89             }
     90         }
     91 
     92         return ret;
     93     }
     94 
     95     bool remove(int i)   // O(n)
     96     {
     97         bool ret = ((0 <= i) && (i < m_length));
     98 
     99         if( ret )
    100         {
    101             SmartPointer<Node> current = position(i);
    102 
    103             SmartPointer<Node> toDel = current->next;
    104 
    105             if( m_current == toDel )
    106             {
    107                 m_current = toDel->next;
    108             }
    109 
    110             current->next = toDel->next;
    111 
    112             m_length--;
    113 
    114             // destroy(toDel);
    115 
    116         }
    117 
    118         return ret;
    119     }
    120 
    121     bool set(int i, const T& e)   //  O(n)
    122     {
    123         bool ret = ((0 <= i) && (i < m_length));
    124 
    125         if( ret )
    126         {
    127             position(i)->next->value = e;
    128         }
    129 
    130         return ret;
    131     }
    132 
    133     T get(int i) const
    134     {
    135         T ret;
    136 
    137         if( get(i, ret) )
    138         {
    139             return ret;
    140         }
    141         else
    142         {
    143             THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
    144         }
    145 
    146         return ret;
    147     }
    148 
    149     bool get(int i, T& e) const    // O(n)
    150     {
    151         bool ret = ((0 <= i) && (i < m_length));
    152 
    153         if( ret )
    154         {
    155             e = position(i)->next->value;
    156         }
    157 
    158         return ret;
    159     }
    160 
    161     int find(const T& e) const    //  O(n)
    162     {
    163         int ret = -1;
    164         int i = 0;
    165 
    166         SmartPointer<Node> node = m_header.next;
    167 
    168         //while( node )
    169         while( node.isNull() )
    170         {
    171             if( node->value == e )
    172             {
    173                 ret = i;
    174                 break;
    175             }
    176             else
    177             {
    178                 node = node->next;
    179                 i++;
    180             }
    181         }
    182 
    183         return ret;
    184     }
    185 
    186     int length() const   // O(1)
    187     {
    188         return m_length;
    189     }
    190 
    191     void clear()    //  O(n)
    192     {
    193         //while( m_header.next )
    194         while( m_header.next.isNull() )
    195         {
    196             //Node* toDel = m_header.next;
    197             SmartPointer<Node> toDel = m_header.next;
    198 
    199             m_header.next = toDel->next;
    200 
    201             m_length--;
    202 
    203             // destroy(toDel);
    204         }
    205 
    206         // m_length = 0;
    207     }
    208 
    209     bool move(int i, int step = 1)
    210     {
    211         bool ret = (0 <= i) && (i < m_length) && (step > 0);
    212 
    213         if( ret )
    214         {
    215             m_current = position(i)->next;
    216             m_step = step;
    217         }
    218 
    219         return ret;
    220     }
    221 
    222     bool end()
    223     {
    224         //return (m_current == NULL);
    225         return m_current.isNull();
    226     }
    227 
    228     T current()
    229     {
    230         if( !end() )
    231         {
    232             return m_current->value;
    233         }
    234         else
    235         {
    236             THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
    237         }
    238     }
    239 
    240     bool next()   //每次移动step步
    241     {
    242         int i = 0;
    243 
    244         while((i < m_step) && !end())
    245         {
    246             m_current = m_current->next;
    247             i++;
    248         }
    249 
    250         return (i == m_step);
    251     }
    252 
    253     ~LinkList()   //  O(n)
    254     {
    255         clear();
    256     }
    257 };
    258 
    259 }
    260 
    261 #endif // LINKLIST_H

    测试程序如下:

     1 #include <iostream>
     2 #include "LinkList.h"
     3 
     4 using namespace std;
     5 using namespace DTLib;
     6 
     7 
     8 int main()
     9 {
    10     LinkList<int> list;
    11 
    12     for(int i = 0; i < list.length(); i++)
    13     {
    14         list.insert(i);
    15     }
    16 
    17     for(list.move(0); !list.end(); list.next())
    18     {
    19         cout << list.current() << endl;
    20     }
    21 
    22     return 0;
    23 }

    运行结果如下:

    程序直接崩溃了。

     我们的SmartPointer设计中,一片堆空间最多只能由一个指针标识,但是我们设计的和遍历有关的函数,例如move、end、current、next,在遍历时一片堆空间会由多个指针指向,所以程序崩溃了。

    改进方案:

    我们需要创建一个中间类pointer,并且它还有两个子类。

    SharedPointer支持一片堆空间由多个指针指向,也支持自动释放。

    在设计上做了改动,所以SmartPointer也得做改动。

    pointer类中的析构函数是纯虚函数,因为pointer是一个抽象父类,需要由子类继承才能生成对象。

    Object的析构函数就是纯虚的,所以pointer中就没有必要再写一遍了。

    只要pointer没有实现自己的析构函数,那么它就还是一个抽象类。

    添加Pointer.h文件,内容如下:

     1 #ifndef POINTER_H
     2 #define POINTER_H
     3 
     4 #include "Object.h"
     5 
     6 namespace DTLib
     7 {
     8 
     9 template < typename T >
    10 class Pointer : public Object
    11 {
    12 protected:
    13     T* m_pointer;
    14 
    15 public:
    16     Pointer(T* p = NULL)
    17     {
    18         m_pointer = p;
    19     }
    20 
    21     T* operator->()
    22     {
    23         return m_pointer;
    24     }
    25 
    26     T& operator* ()
    27     {
    28         return *m_pointer;
    29     }
    30 
    31     bool isNull()
    32     {
    33         return (m_pointer == NULL);
    34     }
    35 
    36     T* get()
    37     {
    38         return m_pointer;
    39     }
    40 
    41     // 不需要析构函数,这里继承自Object,只要不实现具体的析构函数,这个类就是抽象类
    42 };
    43 
    44 }
    45 
    46 #endif // POINTER_H

    SmartPointer.h的内容更改如下:

     1 #ifndef SMARTPOINTER_H
     2 #define SMARTPOINTER_H
     3 
     4 #include "Pointer.h"
     5 
     6 namespace DTLib
     7 {
     8 
     9 template <typename T>
    10 class SmartPointer : public Pointer<T>
    11 {
    12 public:
    13     SmartPointer(T *p = NULL) : Pointer<T>(p)
    14     {
    15 
    16     }
    17 
    18     SmartPointer(const SmartPointer<T>& obj)
    19     {
    20         this->m_pointer = obj.m_pointer;
    21 
    22         const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
    23     }
    24 
    25     SmartPointer<T>& operator= (const SmartPointer<T>& obj)
    26     {
    27         if(this != &obj)
    28         {
    29             T* p = this->m_pointer;
    30 
    31             this->m_pointer = obj.m_pointer;
    32 
    33             const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
    34 
    35             delete p;
    36         }
    37 
    38         return *this;
    39     }
    40 
    41     ~SmartPointer()   // 肯定需要这个析构函数,否则还是抽象类
    42     {
    43         delete this->m_pointer;
    44     }
    45 };
    46 
    47 }
    48 
    49 #endif // SMARTPOINTER_H

    第25-36行的赋值操作符改成了异常安全的,将delete操作放到了最后。

    SmartPointer.h中删掉了一些重载函数,放到了Pointer.h中,SmartPointer继承自Pointer。

    测试程序如下:

     1 #include <iostream>
     2 #include "SmartPointer.h"
     3 
     4 using namespace std;
     5 using namespace DTLib;
     6 
     7 
     8 class Test : public Object
     9 {
    10 public:
    11     Test()
    12     {
    13         cout << "Test()" << endl;
    14     }
    15 
    16     ~Test()
    17     {
    18         cout << "~Test()" << endl;
    19     }
    20 };
    21 
    22 int main()
    23 {
    24     SmartPointer<Test> sp = new Test();
    25 
    26     return 0;
    27 }

    结果如下:

    可以看到自动调用了Test的析构函数。

    思考:

  • 相关阅读:
    iOS 最新版 CocoaPods 的安装流程
    AFNetworking 3.0.4 的使用
    NSPredicate谓词
    PHP基本类型操作
    MJExtension使用指导(转)
    字典转模型KVC和runtime二者实现与区别
    iOS之KVC字典转模型的底层实现
    runtime 总结(原创)
    Objective-C Runtime能做什么?
    Runtime那些事儿(消息机制)
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9652199.html
Copyright © 2011-2022 走看看