zoukankan      html  css  js  c++  java
  • 指针对象C++ primer智能指针(HasPtr)实现

    最近应用开发的过程中涌现了一个小问题,顺便记录一下原因和方法--指针对象

        

    智能指针显然是C++吸引人的地方之一,必须握掌。看了《C++primer》,里头侧重讲了智能指针的现实式方。

        

    书中说到:

        

        “HasPtr(注:就是自定义的智能指针)在其它方面的行为与一般指针分歧。体具而言,复制对象时,副本和原对象将向指统一基本对象。如果通过一个副本变改基本对象,则通过另一个对象问访的值也会变改。

        

          新的HasPtr类须要一个析构函数来删除指针。但是,析构函数不能无条件的删除指针。”

        

         条件就是用引计数。如果该对象被两个指针所指,那么删除其中一个指针,并不会用调该指针的析构函数,因为此时还有另外一个指针向指该对象。看来,智能指针主要是防预不当的析构行为,避免涌现悬垂指针。

        

    指针和对象

        

        如上图所示,HasPtr就是智能指针,U_Ptr为计数器,定义如下:

        

        

    [cpp]  view plain copy
     
    1. class U_Ptr {  
    2.     friend class HasPtr;  
    3.     int *ip;  
    4.     size_t use;  
    5.     U_Ptr(int *p) :  
    6.         ip(p), use(1) {  
    7.         cout << "U_ptr constructor called !" << endl;  
    8.     }  
    9.     ~U_Ptr() {  
    10.         delete ip;  
    11.         cout << "U_ptr distructor called !" << endl;  
    12.     }  
    13. };  

        里头有个变量use和指针ip: use记录了*ip对象被多少个HasPtr对象所指。设假在现又两个HasPtr对象p1,p2向指了U_Ptr,那么在现我delete  p1,use变量将自减1,  

        U_Ptr

        不会析构,那么U_Ptr向指的对象也不会析构,那么p2仍然向指了来原的对象,而不会酿成一个空悬指针。当delete p2的时候,use变量将自减1,为0。此时,U_Ptr对象行进析构,那么U_Ptr向指的对象也行进析构,证保不会存内露泄。 

      

        

        

    包括指针的类须要特别意注复制制控,原因是复制指针时只复制指针中的地址,而不会复制指针向指的对象。

        

    大多数C++类用三种方法之一管理指针成员

        

        (1)不管指针成员。复制时只复制指针,不复制指针向指的对象。当其中一个指针把其向指的对象的空间释放后,其它指针都成了悬浮指针。这是一种极端

        

       (2)当复制的时候,即复制指针,也复制指针向指的对象。这样可能成造空间的费浪。因为指针向指的对象的复制不定一是必要的。

        

       (3)第三种就是一种折衷的式方。用利一个辅助类来管理指针的复制。来原的类中有一个指针向指辅助类,辅助类的数据成员是一个计数器和一个指针(向指来原的)(此为本次智能指针现实式方)。

        

         其实,智能指针的用引计数类似于java的圾垃回收制机:java的圾垃的定判很简答,如果一个对象没有用引所指,那么该对象为圾垃。系统就能够回收了

        

     

        

    [cpp]  view plain copy
     
    1. # include <iostream>  
    2. using namespace std;  
    3. class U_Ptr {  
    4.     friend class HasPtr;  
    5.     int *ip;  
    6.     size_t use;  
    7.     U_Ptr(int *p) :  
    8.         ip(p), use(1) {  
    9.         cout << "U_ptr constructor called !" << endl;  
    10.     }  
    11.     ~U_Ptr() {  
    12.         delete ip;  
    13.         cout << "U_ptr distructor called !" << endl;  
    14.     }  
    15. };  
    16. class HasPtr {  
    17. public:  
    18.     HasPtr(int *p, int i) :  
    19.         ptr(new U_Ptr(p)), val(i) {  
    20.         cout << "HasPtr constructor called ! " << "use = " << ptr->use << endl;  
    21.     }  
    22.     HasPtr(const HasPtr& orig) :  
    23.         ptr(orig.ptr), val(orig.val) {  
    24.         ++ptr->use;  
    25.         cout << "HasPtr copy constructor called ! " << "use = " << ptr->use  
    26.                 << endl;  
    27.     }  
    28.     HasPtr& operator=(const HasPtr&);  
    29.     ~HasPtr() {  
    30.         cout << "HasPtr distructor called ! " << "use = " << ptr->use << endl;  
    31.         if (--ptr->use == 0)  
    32.             delete ptr;  
    33.     }  
    34.     int *get_ptr() const {  
    35.         return ptr->ip;  
    36.     }  
    37.     int get_int() const {  
    38.         return val;  
    39.     }  
    40.     void set_ptr(int *p) const {  
    41.         ptr->ip = p;  
    42.     }  
    43.     void set_int(int i) {  
    44.         val = i;  
    45.     }  
    46.     int get_ptr_val() const {  
    47.         return *ptr->ip;  
    48.     }  
    49.     void set_ptr_val(int i) {  
    50.         *ptr->ip = i;  
    51.     }  
    52. private:  
    53.     U_Ptr *ptr;  
    54.     int val;  
    55. };  
    56. HasPtr& HasPtr::operator =(const HasPtr &rhs) {     //意注,这里赋值操纵符在增加做操纵数的应用计数之前使rhs的应用技巧加1,从而避免自我赋值  
    57.     ++rhs.ptr->use;  
    58.     if (--ptr->use == 0)  
    59.         delete ptr;  
    60.     ptr = rhs.ptr;  
    61.     val = rhs.val;  
    62.     return *this;  
    63. }  
    64. int main() {  
    65.     int *pi = new int(0);  
    66.     HasPtr *hpa = new HasPtr(pi, 100);  
    67.     HasPtr *hpb = new HasPtr(*hpa);  
    68.     HasPtr *hpc = new HasPtr(*hpb);  
    69.     HasPtr hpd = *hpa;  
    70.   
    71.     cout << hpa->get_ptr_val() << " " << hpb->get_ptr_val() << endl;  
    72.     hpc->set_ptr_val(10000);  
    73.     cout << hpa->get_ptr_val() << " " << hpb->get_ptr_val() << endl;  
    74.     hpd.set_ptr_val(10);  
    75.     cout << hpa->get_ptr_val() << " " << hpb->get_ptr_val() << endl;  
    76.     delete hpa;  
    77.     delete hpb;  
    78.     delete hpc;  
    79.     cout << hpd.get_ptr_val() << endl;  
    80.     return 0;  
    81. }  
        每日一道理
    一个安静的夜晚,我独自一人,有些空虚,有些凄凉。坐在星空下,抬头仰望美丽天空,感觉真实却由虚幻,闪闪烁烁,似乎看来还有些跳动。美的一切总在瞬间,如同“海市蜃楼”般,也只是刹那间的一闪而过,当天空变得明亮,而这星星也早已一同退去……

        

    这里的赋值操纵符比拟费事,且让我用图表分析一番:

        

    设假在现又两个智能指针p1, p2,一个向指容内为42的存内,一个向指容内为100的存内,如下图:

        

    指针和对象

        

    在现,我要做赋值操纵,p2 = p1。比对着上面的

        

    [cpp]  view plain copy
     
    1. HasPtr& HasPtr::operator =(const HasPtr &rhs)  

        此时,rhs就是p1,首先将p1向指的ptr的use加1,

        

    [cpp]  view plain copy
     
    1. ++rhs.ptr->use;  

        然后,做:

        

     

        

     

        

    [cpp]  view plain copy
     
    1. if (--ptr->use == 0)  
    2.         delete ptr;  

        因为,本来p2向指的对象在现p2不在向指,那么该对象就少了一个指针去指,所以,use做自减1;

        

        

     

        

    此时,条件立成。因为u2的use为1。那么,运行U_Ptr的析构函数,而在U_Ptr的析构函数中,做了delete ip操纵,所以释放了存内,不会有存内露泄的问题。

        

    接下来的操纵很天然,无需多言:

        

     

        

    [cpp]  view plain copy
     
    1. ptr = rhs.ptr;  
    2. val = rhs.val;  
    3. return *this;  

        做完赋值操纵后,那么就成为如下图所示了。红色标注的就是化变的分部:

        

     

        

    指针和对象

        

    而还要意注的是,重载赋值操纵符的时候,定一要意注的是,检查自我赋值的情况。

        

    如图所示:

        

    指针和对象

        

    此时,做p1 = p1的操纵。那么,首先u1.use自增1,为2;然后,u1.use自减1,为1。那么就不会行执delete操纵,剩下的操纵都可以顺利行进。按《C++ primer》说法,“这个赋值操纵符在增加左操纵数的应用计数之前使rhs的应用计数加1,从而避免自身赋值”。哎,正反我是那样懂得的。当然,一来就能够按规常那样:

        

     

        

    [cpp]  view plain copy
     
    1. ifthis == &rhs)  
    2.     return *this;  

        

     

        

    运行结果:

        

    U_ptr constructor called !
    HasPtr constructor called ! use = 1
    HasPtr copy constructor called ! use = 2
    HasPtr copy constructor called ! use = 3
    HasPtr copy constructor called ! use = 4
    0 0
    10000 10000
    10 10
    HasPtr distructor called ! use = 4
    HasPtr distructor called ! use = 3
    HasPtr distructor called ! use = 2
    10
    HasPtr distructor called ! use = 1
    U_ptr distructor called !

        

    转载于:http://blog.csdn.net/randyjiawenjie/article/details/6723367

    文章结束给大家分享下程序员的一些笑话语录: 看到有人回帖“不顶不是中国人”,他的本意是想让帖子沉了。

  • 相关阅读:
    springboot文件上传: 单个文件上传 和 多个文件上传
    Eclipse:很不错的插件-devStyle,将你的eclipse变成idea风格
    springboot项目搭建:结构和入门程序
    POJ 3169 Layout 差分约束系统
    POJ 3723 Conscription 最小生成树
    POJ 3255 Roadblocks 次短路
    UVA 11367 Full Tank? 最短路
    UVA 10269 Adventure of Super Mario 最短路
    UVA 10603 Fill 最短路
    POJ 2431 Expedition 优先队列
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3069868.html
Copyright © 2011-2022 走看看