Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

C++类中的指针成员管理

$
0
0

      C++类中经常含有指针,但是如何处理这个问题,本文针对<<C++ Primer>>和<<C++沉思录>>的方法进行了一点小结,本文只是浅尝辄止,深了自己都不懂了,且本文的例子漏洞百出,本文旨在总结这几种处理方法。

 

类中含有指针带来的一些问题

     设计具有指针成员的类时,类设计者必须首先需要决定的是该指针应提供什么行为。将一个指针复制到另一个指针时,两个指针指向同一个对象。当两个指针指向同一对象时,可以实用任一指针改变对象。类似地,很可能一个指针了一个对象时,另一个指针的用户还没有发现。

      通过不同的复制控制策略,可以为指针成员实现不同的行为。通常有以下五种策略(个人之见):

    (1)指针成员采取常规指针行为。这样的类具有所有指针缺限,但是不需要用户编写复制控制程序;

    (2)类采取值行为。复制的时候,另外分配空间,但是值与被复制对象一致;

    (3)采取拥有权转移。即被复制对象释放指针的引用。标准库的auto_ptr;

    (4)实现所谓的“智能指针”。共享对象,但是能防止“悬垂指针”;

    (5)“写时复制”技术。在修改的时候才去重新分配空间。

 

策略一:常规指针行为

      这种方式的赋值操作符/复制构造函数采用系统默认的,两个复制的对象共用相同的空间,这会带来一些析构时遇到的问题。

#include<iostream>
using namespace std;
 
class HasPtr{
public:
     HasPtr(int *p):ptr(p){}
     int* getPtr()const
     {return ptr;}
     void setPtr(int *p)
     {ptr = p;}
     int& operator*()//返回引用可以对其赋值
     {return *ptr;}
     const int& operator*()const
     {return *ptr;}
     int* operator->()
     {return ptr;}
     const int* operator->()const
     {return ptr;}
     ~ HasPtr(){delete ptr;}
private:
     int *ptr;
};
 
int main()
{
    HasPtr p1(new int(5));
    HasPtr p2(p1);
    *p1 = 12;
    cout<<*p1<<endl;//5
    cout<<*(p2.operator->())<<endl;//12
    system("pause");
    return 0;
}



策略二:“值复制”行为

       这种方式在复制的时候,采用“值复制”的方式。即复制的时候不复制空间指针,而是重新分配空间,但是其“值”与被复制的对象“值”一样。一般笔试时,string可以采用这种类型。


/*copyright@ CNV && lsj*/
 
#include<iostream>
using namespace std;
 
class HasPtr{
public:
    HasPtr(int *p):ptr(p){}
    HasPtr(const HasPtr& other):ptr(new int(*other))
    {}
    HasPtr& operator=(const HasPtr& other)
    {
       *ptr = *other;
       return *this;
    }
    int& operator*()//返回引用可以对其赋值
    {return *ptr;}
    const int& operator*()const
    {return *ptr;}
    int* operator->()
    {return ptr;}
    const int* operator->()const
    {return ptr;}
    ~ HasPtr(){delete ptr;}
private:
    int *ptr;
};
 
int main()
{
    HasPtr p1(new int(5));
    HasPtr p2(p1);
    *p2 = 13;
    cout<<*p1<<endl;//5
    cout<<*p2<<endl;//13
    system("pause");
    return 0;
}
 


策略三:拥有权转移行为

      被复制的对象释放对指针的拥有权,由左边对象接管指针的拥有权。标准库auto_ptr采用了这种策略。

/*copyright@ CNV && lsj*/
 
#include<iostream>
using namespace std;
 
class HasPtr{
public:
   HasPtr(int *p):ptr(p){}
   HasPtr(const HasPtr& other)
   {
      ptr = other.getPtr();
      other.setPtr(NULL);
   }
 
   HasPtr& operator=(const HasPtr&other)
   {
      if(&other!=this){
          ptr = other.getPtr();
          other.setPtr(NULL);
       }
       return *this;
   }
   int getPtr()const
   {return ptr;}
    void setPtr(int *p)
   {ptr = p;}
   ~ HasPtr()
   {
       if(ptr)delete ptr;
   }
private:
    int *ptr;
};



策略四:智能指针行为

     这种策略虽然还是采用多个对象共享同一份地址空间,但是通过给类添加计数器,能够有效的防止“悬垂指针”。实现智能指针有两种方案(C++ Primer):计数伙伴类和句柄类。

方案1:设计伙伴计数类。

/*copyright@ CNV && lsj*/
 
#include<iostream>
using namespace std;
 
class HasPtr;
class Uptr{//计数伙伴类
    friend class HasPtr;
    int *ip;//本来应该包含这个指针
    size_t use;
    Uptr(int *p):ip(p),use(1)
    {}
    ~Uptr(){delete ip;}
};
 
class HasPtr{
public:
    HasPtr(int *p):ptr(new Uptr(p))
    {}
    HasPtr(const HasPtr& other){
       ptr = other.ptr;
       ++ptr->use;
    }
    HasPtr operator=(const HasPtr&other){
       ++other.ptr->use;
       if(--ptr->use==0)
          delete ptr;
       ptr = other.ptr;
       return *this;
     }
     int& operator *()
     { return *(ptr->ip);}

     ~ HasPtr(){
          If(--ptr->use==0)
              delete ptr; //将调用伙伴类的析构函数
      }
private:
   Uptr *ptr;//将int类型的指针封装到伙伴类中
};
 
int main()
{
    HasPtr p1(new int(3));
    HasPtr p2 = p1;
    *p2 = 5;
    cout<<*p1<<endl;//5
    system("pause");
    return 0;
}



方案2:计数器封装到当前类中,但是计数器use必须采用指针,这样各个指向同一个指针的对象共享同一份空间,都可以去改这个计数器

/*copyright@ CNV && lsj*/
 
#include<iostream>
using namespace std;
 
class HasPtr{
public:
    HasPtr(int*p):ptr(p),use(new int(1))
    {}
    HasPtr(constHasPtr& other)
    {
        ptr= other.ptr;     
        use= other.use;
        ++*use;
    }
    HasPtr&operator=(const HasPtr& other){           
        ++*other.use;
        if(--*use==0){
            deleteptr;
            deleteuse;
         }                
         ptr= other.ptr;
         use= other.use;
         return*this;
     }
     int& operator *()
     {
           return *ptr;
     }
     ~HasPtr()
      {
          if(--*use==0)
          {
               deleteptr;
               deleteuse;
           }
       }
private:
     int *ptr;//所包含元素的指针
     //一定要用指针,这样大家共用一份空间,都可以改写
     int *use;
};



策略五:写时复制计数

     有时候用户需要对象与对象之间的空间独立,但是每次都复制开销又很大。采用的策略是先不急着复制空间,拖到当另一个类要改写共享空间的时候,复制出来一份改写。

/*copyright@ CNV && lsj*/
 
#include<iostream>
using namespace std;
 
class HasPtr{
public:
    HasPtr(int*p):ptr(p),use(new int(1))
    {}
    HasPtr(constHasPtr& other){
       ptr= other.ptr;
       use= other.use;
       ++*use;
    }
    HasPtr& operator=(const HasPtr& other){
       ++*other.use;
       if(--*use==0){
           delete ptr;
           delete use;
        }                
        ptr= other.ptr;
        use= other.use;
        return *this;
    }
    int& operator *()
    {
        return*ptr;
    }
    ~HasPtr()
    {
        if(--*use==0)
        {
           delete ptr;
           delete use;
         }
     }
     //这个接口要改写共享空间,此时复制一份改写
    void setValue(intval)
    {
        //判断是不是只有当前对象持有共享空间
        //如果是,则不用复制,直接改
        if(*use!=1){
            --*use;
            use= new int(1);
            ptr= new int(val);
         }
         *ptr= val;
     }
private:
    int *ptr;//所包含元素的指针
    //一定要用指针,这样大家共用一份空间,都可以改写
    int *use;
};
 
int main()
{
    HasPtr p1(newint(3));
    HasPtr p2= p1;
    p2.setValue(5);
    cout<<*p1<<endl;//5
    system("pause");
    return 0;
}



作者:u010064842 发表于2013-8-2 16:58:36 原文链接
阅读:42 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles