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 == ©) //應該判斷是否與地址相同
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 == ©) //應該判斷是否與地址相同
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 ;
}