zoukankan      html  css  js  c++  java
  • 用c++简单实现智能指针(转)

    http://blog.csdn.net/xinpo66/article/details/8786057

    用c++简单实现智能指针

          什么是智能指针?答案相当简单;智能指针是聪明的普通指针。这是什么意思?实际上,智能指针是一些对象,表现出普通指针的功能但是比普通指针多做了一些事情。这些对象像普通指针一样灵活,并且管理对象有自己的优点(比如构造器和自动析构)。智能指针解决了普通指针的一些问题。

          普通指针的问题。

          我们使用C++语言中的指针,最常见的问题是什么?内存管理吧,请看下面的代码:

    [cpp] view plaincopy
     
    1. char* pName  = new char[1024];  
    2. …  
    3. SetName(pName);  
    4. …  
    5. …  
    6. if(null != pName)  
    7. {  
    8.        delete[] pName;   
    9. }  
     
          好多次我们都会忘记释放pNme,并且管理释放这些不会再用到的指针将会是很大的工程。可不可以指针自身进行管理?当然,智能指针就可以做到。我们实现一个智能指针,看看智能指针如何处理的更好。
          下面写一个实际例子,先写一个叫做Person的类。
         
    [cpp] view plaincopy
     
    1. class Person  
    2. {  
    3.     int age;  
    4.     char* pName;  
    5.   
    6.     public:  
    7.         Person(): pName(0),age(0)  
    8.         {  
    9.         }  
    10.         Person(char* pName, int age): pName(pName), age(age)  
    11.         {  
    12.         }  
    13.         ~Person()  
    14.         {  
    15.         }  
    16.   
    17.         void Display()  
    18.         {  
    19.             printf("Name = %s Age = %d \n", pName, age);  
    20.         }  
    21.         void Shout()  
    22.         {  
    23.             printf("Ooooooooooooooooo");  
    24.         }   
    25. };  

    下面是客户端代码使用Person类。

    [cpp] view plaincopy
     
    1. void main()  
    2. {  
    3.     Person* pPerson  = new Person("Scott", 25);  
    4.     pPerson->Display();  
    5.     delete pPerson;  
    6. }  
    现在我们来看这段代码,每当我创建一个指针,都要管理释放它。我要自动的释放它,智能指针可以。因此我们创建一个SP类来管理Person的对象,客户端的代码可以这样写:

    [cpp] view plaincopy
     
    1. void main()  
    2. {  
    3.     SP p(new Person("Scott", 25));  
    4.     p->Display();  
    5.     // Dont need to delete Person pointer..  
    6. }  

    [cpp] view plaincopy
     
    1. void main()  
    2. {  
    3.     SP p(new Person("Scott", 25));  
    4.     p->Display();  
    5.     // Dont need to delete Person pointer..  
    6. }  

    注意:
         1,我们创建了一个SP对象来管理Person的指针,当SP对象的作用域结束,会自动析构,它将释放Person的指针。
         2,我们可以使用SP的对象p调用Display()函数,就像Person类的对象指针调用Display()函数,它的行为表现的像Person类的对象指针。
    智能指针接口
       智能指针表现出指针的行为,所以应该支持如下运算符:
     
    • Dereferencing (operator *)
    • Indirection (operator ->)
     
    下面实现智能指针SP:
    [cpp] view plaincopy
     
    1. class SP  
    2. {  
    3. private:  
    4.     Person*    pData; // pointer to person class  
    5. public:  
    6.     SP(Person* pValue) : pData(pValue)  
    7.     {  
    8.     }  
    9.     ~SP()  
    10.     {  
    11.         // pointer no longer requried  
    12.         delete pData;  
    13.     }  
    14.   
    15.     Person& operator* ()  
    16.     {  
    17.         return *pData;  
    18.     }  
    19.   
    20.     Person* operator-> ()  
    21.     {      
    22.         return pData;  
    23.     }  
    24. };  

    这就是我们智能指针,当它的析构函数被调用时会释放Person类的对象指针。它也支持类似于指针的操作。
     
    通用的智能指针
     
     
    但是有个问题,我们智能控制Person类,也就是说每一种类型我们都要实现一个智能指针。我们可以使用模版使它通用。
     
    [cpp] view plaincopy
     
    1. template < typename T > class SP  
    2. {  
    3.     private:  
    4.     T*    pData; // Generic pointer to be stored  
    5.     public:  
    6.     SP(T* pValue) : pData(pValue)  
    7.     {  
    8.     }  
    9.     ~SP()  
    10.     {  
    11.         delete pData;  
    12.     }  
    13.   
    14.     T& operator* ()  
    15.     {  
    16.         return *pData;  
    17.     }  
    18.   
    19.     T* operator-> ()  
    20.     {  
    21.         return pData;  
    22.     }  
    23. };  
    24.   
    25. void main()  
    26. {  
    27.     SP<Person> p(new Person("Scott", 25));  
    28.     p->Display();  
    29.     // Dont need to delete Person pointer..  
    30. }  

    我们的智能指针这样就真的智能了吗?验证下面的代码:
    [cpp] view plaincopy
     
    1. void main()  
    2. {  
    3.     SP<Person> p(new Person("Scott", 25));  
    4.     p->Display();  
    5.     {  
    6.         SP<Person> q = p;  
    7.         q->Display();  
    8.         // Destructor of Q will be called here..  
    9.     }  
    10.     p->Display();  
    11. }  

    这样就会存在一个问题:p和q关联到了Person类的相同对象指针,当q结束它的作用域时会释放Person类的对象指针,我们用p调用Display()函数会因为垂悬指针而失败。我们应该在不使用它的时候再释放,智能指针中引入计数便可解决。
     
    计数器。
    下面实现一个计数器的类RC.
    [cpp] view plaincopy
     
    1. class RC  
    2. {  
    3.     private:  
    4.     int count; // Reference count  
    5.   
    6.     public:  
    7.     void AddRef()  
    8.     {  
    9.         // Increment the reference count  
    10.         count++;  
    11.     }  
    12.   
    13.     int Release()  
    14.     {  
    15.         // Decrement the reference count and  
    16.         // return the reference count.  
    17.         return --count;  
    18.     }  
    19. };  

    下面把计数器引入到我们的智能指针中:
    [cpp] view plaincopy
     
    1. template < typename T > class SP  
    2. {  
    3. private:  
    4.     T*    pData;       // pointer  
    5.     RC* reference; // Reference count  
    6.   
    7. public:  
    8.     SP() : pData(0), reference(0)   
    9.     {  
    10.         // Create a new reference   
    11.         reference = new RC();  
    12.         // Increment the reference count  
    13.         reference->AddRef();  
    14.     }  
    15.   
    16.     SP(T* pValue) : pData(pValue), reference(0)  
    17.     {  
    18.         // Create a new reference   
    19.         reference = new RC();  
    20.         // Increment the reference count  
    21.         reference->AddRef();  
    22.     }  
    23.   
    24.     SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference)  
    25.     {  
    26.         // Copy constructor  
    27.         // Copy the data and reference pointer  
    28.         // and increment the reference count  
    29.         reference->AddRef();  
    30.     }  
    31.   
    32.     ~SP()  
    33.     {  
    34.         // Destructor  
    35.         // Decrement the reference count  
    36.         // if reference become zero delete the data  
    37.         if(reference->Release() == 0)  
    38.         {  
    39.             delete pData;  
    40.             delete reference;  
    41.         }  
    42.     }  
    43.   
    44.     T& operator* ()  
    45.     {  
    46.         return *pData;  
    47.     }  
    48.   
    49.     T* operator-> ()  
    50.     {  
    51.         return pData;  
    52.     }  
    53.       
    54.     SP<T>& operator = (const SP<T>& sp)  
    55.     {  
    56.         // Assignment operator  
    57.         if (this != &sp) // Avoid self assignment  
    58.         {  
    59.             // Decrement the old reference count  
    60.             // if reference become zero delete the old data  
    61.             if(reference->Release() == 0)  
    62.             {  
    63.                 delete pData;  
    64.                 delete reference;  
    65.             }  
    66.   
    67.             // Copy the data and reference pointer  
    68.             // and increment the reference count  
    69.             pData = sp.pData;  
    70.             reference = sp.reference;  
    71.             reference->AddRef();  
    72.         }  
    73.         return *this;  
    74.     }  
    75. };  

    在看看客户端的代码:
    [cpp] view plaincopy
     
    1. Collapse | Copy Code  
    2. void main()  
    3. {  
    4.     SP<PERSON> p(new Person("Scott", 25));  
    5.     p->Display();  
    6.     {  
    7.         SP<PERSON> q = p;  
    8.         q->Display();  
    9.         // Destructor of q will be called here..  
    10.   
    11.         SP<PERSON> r;  
    12.         r = p;  
    13.         r->Display();  
    14.         // Destructor of r will be called here..  
    15.     }  
    16.     p->Display();  
    17.     // Destructor of p will be called here   
    18.     // and person pointer will be deleted  
    19. }  

     

  • 相关阅读:
    jsmin Javascript 的小巧的压缩工具
    pChart 支持中文显示
    使用 SyntaxHighlighter 实现代码高亮
    Linux Ubuntu 下阅读 CHM
    QueryPath Method Summary_方法速查手册
    QueryPath PHP 中的 jQuery
    SQL SELECT DISTINCT 语句
    写网页内容需要注意些什么?
    jQuery UI 弹出注册窗口_练习
    Smarty 中的 Foreach
  • 原文地址:https://www.cnblogs.com/wainiwann/p/3066275.html
Copyright © 2011-2022 走看看