1. 程式人生 > >為物件動態分配記憶體

為物件動態分配記憶體

如果類中的資料成員含有指標變數,就需要為指標變數分配動態記憶體。(通常在程式設計中,應該儘量避免使用指標,應該用容器替代指標)

在本例中,使用二重指標,可以視為一個二維陣列,不過該陣列的元素個數可變。

如下為為指標分配空間的建構函式;

//建構函式,建立一個可以指定長度和高度的二維陣列
SpreadSheet::SpreadSheet(int height, int length)
{
	mCells = new SpreadCell* [length];
	
	for(int i = 0; i < length; i++)
	{
		mCells[i] = new SpreadCell[height];
	}
}

在此建構函式中,想為指標陣列分配空間,在為每個指標陣列中的元素分配空間。

釋放指標空間的解構函式定義如下:

//解構函式,先刪除length個一維指標,再刪除一個二維指標
SpreadSheet::~SpreadSheet()
{
	for(int i = 0; i < length; i++)
	{
		//mCells[i]是指標陣列首地址,刪除此指標陣列中的所有元素。
		delete [] mCells[i];
	}
	
	delete mCells;
}

由於mCells[i]相當於一個指標陣列的頭地址,mCells[i][0-j]都對應一個元素,所以刪除該指標使用了刪除陣列指標的方法

delete [] mCells

刪除指標陣列之後,再刪除該指向該指標陣列的指標mCells。

 

預設情況下,在含有指標陣列的物件中,物件的複製是淺複製,容易形成野指標。避免這種情況的話,就要在物件複製之前,先為物件分配空間,進行深複製。物件的賦值與此類似。以下程式碼為物件的複製操作。

//複製建構函式
SpreadSheet::SpreadSheet(const SpreadSheet& src)
{
	copyFrom(src);
}

其中,copyFrom(src)為輔助函式,不僅分配記憶體,還為記憶體裡的元素賦值。其定義如下:

//輔助copy函式
void SpreadSheet::copyFrom(const SpreadSheet& src)
{
	height = src.height;
	length = src.length;
	
	//分配length個堆空間,每個堆空間儲存一個指向SpreadCell的指標
	mCells = new SpreadCell* [length];
	for (int i = 0; i < length; i++)
	{
		//分配height個堆空間,每個堆空間儲存一個SpreadCell物件。
		mCells[i] = new SpreadCell[height];
	}
	
	for(int i = 0; i < length; i++)
	{
		for(int j = 0; j < height; j++)
		{
			mCells[i][j] = src.mCells[i][j];
		}
	}
}

上述程式碼就是先為本物件分配空間,在給物件內的空間賦值,很容易理解。如下為物件賦值的定義,在copyFrom之前,先進行了自賦值判斷。

//物件賦值
SpreadSheet& SpreadSheet::operator =(const SpreadSheet& rhs)
{
	if(this == &rhs)
	{
		return *this;
	}
	else
	{
		copyFrom(rhs);
		return *this;
	}
}

整體程式如下所示:

#include <iostream>
#include <string>

using namespace std;

class SpreadCell
{
	private:
		int value;
	
	public:
		SpreadCell(): value(0) {};
		SpreadCell(int a): value(a) {};
		
		void setValue(const int& a);
		int getValue() const;
};

//賦值給其它值的形參都可以這樣定義
void SpreadCell::setValue(const int &a)
{
	value = a;
}

//const的作用,保證該函式不修改資料成員
int SpreadCell::getValue() const
{
	return value;
}

class SpreadSheet
{
	private: 
		int height;
		int length;
		SpreadCell **mCells;
		
		void copyFrom(const SpreadSheet &src);
		
	public:
		//~ SpreadSheet();
		SpreadSheet(int height = 4, int length = 5);
		SpreadSheet(const SpreadSheet& src);
		virtual ~SpreadSheet();
		SpreadSheet& operator = (const SpreadSheet& rhs);
		
		void setValue(const int& x, const int& y, const SpreadCell& cell);
		SpreadCell getValue(const int& x, const int& y);
};

//建構函式,建立一個可以指定長度和高度的二維陣列
SpreadSheet::SpreadSheet(int height, int length)
{
	mCells = new SpreadCell* [length];
	
	for(int i = 0; i < length; i++)
	{
		mCells[i] = new SpreadCell[height];
	}
}

//輔助copy函式
void SpreadSheet::copyFrom(const SpreadSheet& src)
{
	height = src.height;
	length = src.length;
	
	//分配length個堆空間,每個堆空間儲存一個指向SpreadCell的指標
	mCells = new SpreadCell* [length];
	for (int i = 0; i < length; i++)
	{
		//分配height個堆空間,每個堆空間儲存一個SpreadCell物件。
		mCells[i] = new SpreadCell[height];
	}
	
	for(int i = 0; i < length; i++)
	{
		for(int j = 0; j < height; j++)
		{
			mCells[i][j] = src.mCells[i][j];
		}
	}
}

//複製建構函式
SpreadSheet::SpreadSheet(const SpreadSheet& src)
{
	copyFrom(src);
}

//物件賦值
SpreadSheet& SpreadSheet::operator =(const SpreadSheet& rhs)
{
	if(this == &rhs)
	{
		return *this;
	}
	else
	{
		copyFrom(rhs);
		return *this;
	}
}

//解構函式,先刪除length個一維指標,再刪除一個二維指標
SpreadSheet::~SpreadSheet()
{
	for(int i = 0; i < length; i++)
	{
		//mCells[i]是指標陣列首地址,刪除此指標陣列中的所有元素。
		delete [] mCells[i];
	}
	
	delete mCells;
}

//在指定位置定義元素
void SpreadSheet::setValue(const int& x, const int& y, const SpreadCell& cell)
{
	mCells[x][y] = cell;
}

//讀取指定位置的元素
SpreadCell SpreadSheet::getValue(const int& x, const int& y)
{
	return mCells[x][y];
}

int main()
{
	SpreadCell a, cell;
	a.setValue(2);
	
	SpreadSheet sc(4, 5);
	
	sc.setValue(1, 2, a);
	cell = sc.getValue(1, 2);
	
	SpreadSheet sc2(sc), sc3;
	sc3 = sc;
	
	cout << "value:" << cell.getValue() << endl;
}