C++ primer 管理指针成员 读书笔记

    在我们编写实际的代码的时候,C++中是尽量不要使用指针的。因为指针是天使和魔鬼的混合体,指针虽然可以带来很高的效率,但是却可以引入很多的麻烦,如悬垂指针,内存泄露等等。当我们必须使用指针的时候,我们该如何掌握指针呢?《C++ primer》这本书总结的有3种方法管理指针成员:

   1.指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。

   2.类可以实现所谓的“智能指针”行为。指针所指向的对象是共享的,但类能够防止悬垂指针。

   3.类采取值型行为。指针所指向的对象是唯一的,由每个类对象独立管理。

 下面我们就将3种情况分别讨论之:

   (1)

为了阐明所涉及的问题,我们将实现一个简单类,该类包含一个 int 值和一个指针:

     // class that has a pointer member that behaves like a plain pointer
     class HasPtr {
     public:
         // copy of the values we're given
         HasPtr(int *p, int i): ptr(p), val(i) { }

         // const members to return the value of the indicated data member
         int *get_ptr() const { return ptr; }
         int get_int() const { return val; }

         // non const members to change the indicated data member
         void set_ptr(int *p) { ptr = p; }
         void set_int(int i) { val = i; }

         // return or change the value pointed to, so ok for const objects
         int get_ptr_val() const { return *ptr; }
         void set_ptr_val(int val) const { *ptr = val; }

     private:
         int *ptr;
         int val;
     };

假如我们自己不定义上面类的复制构造函数,那么指针的默认复制函数将是不可预知的,假如我们比较“高明”一点,在定义复制构造函数时,我们把指针的值也赋值过去,心里暗想,这样应该没有问题了吧,其实不然,书中给了下面这个例子说明潜在的问题,那就是悬垂指针:

     int *ip = new int(42); // dynamically allocated int initialized to 42
     HasPtr ptr(ip, 10);    // Has Ptr points to same object as ip does
     delete ip;             // object pointed to by ip is freed
     ptr.set_ptr_val(0); // disaster: The object to which Has Ptr points was freed!
  (2)

     定义智能指针类:

智能指针除了增加功能外,其行为像普通指针一样。本例中让智能指针负责删除共享对象。用户将动态分配一个对象并将该对象的地址传给新的 HasPtr 类。用户仍然可以通过普通指针访问对象,但绝不能删除指针。HasPtr 类将保证在撤销指向对象的最后一个HasPtr 对象时删除对象。

废话少说,献上书中的代码:

 // private class for use by HasPtr only
     class U_Ptr {
         friend class HasPtr;
         int *ip;
         size_t use;
         U_Ptr(int *p): ip(p), use(1) { }
         ~U_Ptr() { delete ip; }
     };
这是一个私有的类,仅仅能够被HasPtr使用,所以对于其他类是不可见的。很安全的说!

这个时候我们在看看HasPtr类的定义:

class HasPtr {
     public:
         // HasPtr owns the pointer; pmust have been dynamically allocated
         HasPtr(int *p, int i): ptr(new U_Ptr(p)), val(i) { }

         // copy members and increment the use count
         HasPtr(const HasPtr &orig):
            ptr(orig.ptr), val(orig.val) { ++ptr->use; }
         HasPtr& operator=(const HasPtr&);

          int *get_ptr() const { return ptr->ip; }
         int get_int() const { return val; }

         // change the appropriate data member
         void set_ptr(int *p) { ptr->ip = p; }
         void set_int(int i) { val = i; }

         // return or change the value pointed to, so ok for const objects
         // Note: *ptr->ip is equivalent to *(ptr->ip)
         int get_ptr_val() const { return *ptr->ip; }
         void set_ptr_val(int i) { *ptr->ip = i; }


         // if use count goes to zero, delete the U_Ptr object
         ~HasPtr() { if (--ptr->use == 0) delete ptr; }
     private:
         U_Ptr *ptr;        // points to use-counted U_Ptr class
         int val;
     };


可以在上面的析构函数中看出,析构函数并没有直接删除所指的对象,而是在判断智能指针的的计数为0后,将智能指针删除,智能指针的删除将会调用智能指针类的析构函数,从而间接的完成了析构。


(3)

定义值型类

这个比较好理解,上面两种都是复制地址也就是指针的,当其中一个对象改变了所指的内容,那么另一个对象访问的时候肯定是改变后的了。因为是还是指向同一个位置的!但是第三中比较实在,直接把指针所指的内容复制过来,创建一个指针只想他,这样每个对象所指的内容都是一个副本,所以每个对象通过指针改变的都是自己专属的副本,非常安全!也非常浪费内存!这种方法显得很低端啊,我觉得是不是会被编程大牛所鄙视啊~(我是小菜O(∩_∩)O哈哈~)。下面是书中的代码:

 /*
      * Valuelike behavior even though HasPtr has a pointer member:
      * Each time we copy a HasPtr object, we make a new copy of the
      * underlying int object to which ptr points.
      */
     class HasPtr {
     public:
         // no point to passing a pointer if we're going to copy it anyway
         // store pointer to a copy of the object we're given
         HasPtr(const int &p, int i): ptr(new int(p)), val(i) {}

         // copy members and increment the use count
         HasPtr(const HasPtr &orig):
            ptr(new int (*orig.ptr)), val(orig.val) { }

         HasPtr& operator=(const HasPtr&);
         ~HasPtr() { delete ptr; }
         // accessors must change to fetch value from Ptr object
         int get_ptr_val() const { return *ptr; }
         int get_int() const { return val; }

         // change the appropriate data member
         void set_ptr(int *p) { ptr = p; }
         void set_int(int i) { val = i; }

         // return or change the value pointed to, so ok for const objects
         int *get_ptr() const { return ptr; }
         void set_ptr_val(int p) const { *ptr = p; }
     private:
         int *ptr;        // points to an int
         int val;
     };
以上的内容也就这么多了,当然比较粗糙,欢迎大家一起讨论啊



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值