jake1036

面试100 15指针成员的类的copy

         15指针成员的类的copy

 一问题描述
     默认的拷贝构造函数,和拷贝操作符函数,均执行按位copy。即如果将类 A = B ,且AB中有指针成员变量 , 则 A B 两个类的对象,在执行复制操作时,均指向同一处指针位置。若先对A进行析构,则A释放了指针空间。此时B无法访问指针变量。


  注意点:
    (1)如果为一个class添加了新的一个成员变量,那么需要同时修改copying函数。
    (2)需要为子类编写copying函数。必须保证要很小心地复制其base class的成员变量。可以在子类的copying函数中,显式地调用其父类的copying函数。
         但是不允许使用copy操作符函数调用 copy构造函数,两者不能互相调用,若想消除重复,可以使用一个公共函数,进行封装。
               
   

 二 解决方法
     方法1 深度复制
   
#include <iostream>
 
using namespace std ;
 template 
<class T>
 
class Array
 
{
    
private:
       T 
* data ;
       unsigned size ;
     
public :
       Array(unsigned arraySize):data(
0) , size(arraySize)            
       
{
          size 
=  arraySize ;
          data 
= new T(size) ;             
       }

       
       
~Array()
       
{
         
if(data)
           delete [] data ;        
       }
 
       
       
void setValue(int index , const T & value )
       
{
            
if(index < size)
              data[index] 
= value ;
            
       }

       
       T getValue(
int index)
       
{
         
if(index < size)
           
return data[index] ;
         
else 
           
return T() ;  
                        
       }

       
//解决一个拷贝构造函数和赋值函数的方法就是,将这两个函数设置为私有的       
   public :
       Array
<T>( Array<T> & copy):data(0) , size(copy.size)  ///要熟练使用默认参数的构造函数 
       {
          
if(size)
          
{             
           data 
= new T[size];
           
for(int i = 0 ; i < size ;i++)
            setValue(i , copy.getValue(i)) ;
          }
              
       }

     
       
const Array<T> & operator=(const Array<T> & copy)
       
{
          
//首先判断要复制的地址是否一致
          if(this == &copy) //应该判断是否与地址相同   
              return *this ;
             
             
         
//首先判断,this指针所指向的对象的data是否为空,若不为空,需要进行删除缓冲区
          if(data)
           
{
              delete [] data ;
              data 
= 0 ;
                        
           }

           unsigned size 
= copy.size ;
           
if(size)
          
{             
           data 
= new T[size];
           
for(int i = 0 ; i < size ;i++)
            setValue(i , copy.getValue(i)) ;
          }
    
       }
    
       
       
       
 }
 ;
 
 
 
 
int main()
 
{
   Array
<char> A(10) ;
   Array
<char> B(A) ;  // A和B 指向同一块内存,若是先执行对A的析构,则B指向的成员变量内存地址已经不存在,将出现错误 
   system("pause") ;
    
   
return 0 ;    
 }



二  引用计数
       
  使用引用计数技术,若多个对象都使用了同一块内存,则只有所有的对象,都停止使用该对象的时候(即该对象的使用值为0), 该块内存才能被释放。
   
   #include <iostream>
 using namespace std ;
 template <class T>
 class Array
 {
    private:
       T * data ;
       unsigned size ;
       int * count ; //作为引用计数  ,此处应该使用指针,使所有的对象,都指向(共享)同一块内存地址
      
     public :
       Array(unsigned arraySize):data(0) , count(new  int) , size(arraySize)           
       {
          *count = 1 ;           
          size =  arraySize ;
          data = new T(size) ;            
       }
      
       ~Array()
       {
         Release() ;     
       }
      
       void setValue(int index , const T & value )
       {
            if(index < size)
              data[index] = value ;
           
       }
      
       T getValue(int index)
       {
         if(index < size)
           return data[index] ;
         else
           return T() ; 
                       
       }
       //解决一个拷贝构造函数和赋值函数的方法就是,将这两个函数设置为私有的      
 
       Array<T>( Array<T> & copy):data(copy.data) , count(copy.count) , size(copy.size)  ///要熟练使用默认参数的构造函数
       {
          ++(*count) ;            
       }
    
       const Array<T> & operator=(const Array<T> & copy)
       {
          //首先判断要复制的地址是否一致
          if(this == &copy) //应该判断是否与地址相同  
              return *this ;
            
           Release() ;    //需要先删除原来占用的数据区间
           data = copy.data ;
           size = copy.size ;
           count = copy.count ;
           ++(*count) ;
          
         
       }   
    private :
        void Release()
        {
             *(count) -- ;
             if(*count == 0)
             {
              if(data)
              {        
               delete [] data ;
               data = 0 ;
               }
               delete count ; //删除分配的计数内存地址
               count = 0 ;
                       
             }
         
              
        }  
      
      
 } ;
 
 
 
 int main()
 {
   Array<char> A(10) ;
   Array<char> B(10) ;  // A和B 指向同一块内存,若是先执行对A的析构,则B指向的成员变量内存地址已经不存在,将出现错误
   B = A ;
   system("pause") ;
   
   return 0 ;   
 }


posted on 2011-05-17 20:37 kahn 阅读(240) 评论(0)  编辑 收藏 引用 所属分类: 算法相关


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理