線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1561
推到 Plurk!
推到 Facebook!

Matrix Operator 乘法的問題

答題得分者是:aftcast
qqmts0726
一般會員


發表:11
回覆:6
積分:8
註冊:2008-06-27

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-11-15 11:54:38 IP:211.72.xxx.xxx 訂閱
各位大大您好::
小弟最近正在練習撰寫Matrix Operator這各部分,但是發現在結構子部分加上delete的語法的話,會造成回傳值異常,但是如果將delete移除的話,數值就可以正確的跑出來,但記憶體卻不能正常的釋放,所以不知道是哪裡出了問題,已經翻過書但是也好像不是很了解問題點在哪裡。以下是程式碼部分,其中比較特殊的地方是在我讀取Matrix Value 我會利用一個 GetData 及SetData來作傳值,然後儲存的區塊是在FData裡面。

[code cpp]
class FMatrix
{
private:
double *FData;
unsigned int FRow;
unsigned int FCol;
double __fastcall GetData(unsigned int ,unsigned int )const;
void __fastcall SetData(unsigned int ,unsigned int ,double );
public:
FMatrix();
~FMatrix();
void Create(unsigned int ,unsigned int);
bool Set_Count(unsigned int ,unsigned int);
__property double Data[unsigned int Row][unsigned int Col]= {read=GetData, write=SetData};
FMatrix& operator = (const FMatrix &);
FMatrix operator * (FMatrix &);
};

[/code]
[code cpp]
FMatrix::~FMatrix()
{
delete[] FData;
FData=NULL;
FRow=0;
FCol=0;
}
//======================================================
bool FMatrix::Set_Count(unsigned int Row,unsigned int Col)
{
if(Row <= 0 || Col <= 0) return (false);
if(Row==FRow&&Col==FCol) return (true);
FData = new double[Row*Col];
FRow = Row;
FCol = Col;
return true;
}
//======================================================
void FMatrix::Create(unsigned int Row, unsigned int Col)
{
Set_Count(Row,Col);
}
//======================================================
double __fastcall FMatrix::GetData(unsigned int Row,unsigned int Col) const
{
if (Row > 0 && Col > 0 && Row <= FRow && Col <= FCol)
return (FData[FCol*(Row-1) Col-1]);
else
return (0);
}
//======================================================
void __fastcall FMatrix::SetData(unsigned int Row,unsigned int Col,double data)
{
if (Row > 0 && Col > 0 && Row <= FRow && Col <= FCol)
FData[FCol*(Row-1) Col-1] = data;
}
//======================================================
FMatrix& FMatrix::operator = (const FMatrix &Temp)
{
if(Temp.FRow ==FRow && Temp.FCol ==FCol){
for(unsigned int i=1;i<=FRow;i ){
for(unsigned int j=1;j<=FCol;j ){
Data[i][j] = Temp.Data[i][j];
}
}
}
return *this;
}
//======================================================
FMatrix FMatrix::operator* (FMatrix &Temp)
{
FMatrix Result;
unsigned int col;
unsigned int row;
col = Temp.FCol;
row = FRow;
Result.Create(row,col);
for(unsigned int i=1;i<=row;i ){
for(unsigned int j=1;j<=col;j ){
Result.Data[i][j] = 0;
for(unsigned int k=1;k<=FCol;k ){
Result.Data[i][j] = Data[i][k]*Temp.Data[k][j];
}
}
}
return Result;
}
//======================================================

[/code]
編輯記錄
qqmts0726 重新編輯於 2008-11-15 11:55:44, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-11-15 13:25:31 IP:59.115.xxx.xxx 訂閱
看你的class定義都很正常。可否再提供你實際產生instance後產生錯誤的那幾行代碼?
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
qqmts0726
一般會員


發表:11
回覆:6
積分:8
註冊:2008-06-27

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-11-15 19:22:39 IP:118.169.xxx.xxx 訂閱
先感謝大大您的回覆::
在我的測試中
[code cpp]
void __fastcall TForm1::Button1Click(TObject *Sedner)
{
FMatrix A,B;
A.Create(2,2);
B.Create(2,2);
A.Data[1][1] = 1.0;
A.Data[1][2] = 2.0;
A.Data[2][1] = 3.0;
A.Data[2][2] = 4.0;

B.Data[1][1] = 1.0;
B.Data[1][2] = 1.0;
B.Data[2][1] = 1.0;
B.Data[2][2] = 1.0;

B = A * B;
}
[/code]

按照這樣的寫法,所計算出來的答案會是
B.Data[1][1] = 2.8638XXXXXE-31
B.Data[1][2] = 3.0;
B.Data[2][1] = 7.0;
B.Data[2][2] = 7.0;

我有實際去攔截乘法運算retrun 前的計算數值也是正確的,3,3,7,7,
而在解構子 delete前 也是正確的3,3,7,7,
但在delete後,數值就會錯誤了......
跟朋友討論過與參照其他人寫的operator後,
還是不能明確的找出原因點在哪裡?
編輯記錄
qqmts0726 重新編輯於 2008-11-15 19:23:45, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-11-16 04:59:24 IP:59.115.xxx.xxx 訂閱
我也測了好久,compiler表現的情形如同我猜的一樣,return時根本就沒有copy,它只是把一個auto級instance裡的FData指標指給B的FData。然而因為是auto變數,當離開* 算符函數時此instance就會被解構,而此時FData的前幾Bytes就毀了(delete會破壞前幾個bytes),所以總是[1][1]的內容不對!!!

想了很久,又翻起了c 的舊書,突然了解到
1/ 你的class中並沒有copy constructor,在許多情形下compiler會使用到這個constructor。由於本身沒有定義,compiler會自行建一個,但是…
它只會對Data Member做一些初值copy。但是這對*FData指標是不夠的,我們要的不是單純指標的位址被copy而已!

2/所以,compiler用預設的copy形態來return是錯的! 僅管FRow和FCol成員被指為正確值。

3/就自己建立一個copy constructor來解決囉~~ 果然如我所料,compiler在return時會祕密的調用FMatrix(const FMatrix &src); 於是我們有了一個暫時的copy instance(完整的),然後再調用解構子,不過我們已經不怕資料delete了!! 接下來,compiler會用剛暫時的instance copy至B(即處理 B = .......)的動作,。在沒有 = overloading時也正常可以運作喔!

整個過程我並沒有使用 = overloading,我把它remark起來了。我是使用compiler預設的 = 算符來處理,而預設的這個函數也和預設的copy建構子一樣,都只是單純的Data Member的設定。因為暫時的那個instance會在最後才被解構,所以目前看來是沒問題的。當然,用自定的 = overloading 肯定會更好!!

結論: 一切的關鍵點在於return Result; 這行代碼。在沒有自行定義copy constructor時,一切都出呼意料外,僅管你可能認為 = overloading算符可以處理,但是在 = 之前一切就毀了!
附上完整程式碼:

[code cpp]
class FMatrix
{
private:
double *FData;
unsigned int FRow;
unsigned int FCol;
double __fastcall GetData(unsigned int ,unsigned int )const;
void __fastcall SetData(unsigned int ,unsigned int ,double );
public:
FMatrix(){}; //這個inline是我加的,你沒有放{ } 應該compiler不過吧?
FMatrix(const FMatrix &src); //這個建構子是我加入的

~FMatrix();
void Create(unsigned int ,unsigned int);
bool Set_Count(unsigned int ,unsigned int);
__property double Data[unsigned int Row][unsigned int Col]= {read=GetData, write=SetData};
// FMatrix& operator = (const FMatrix &); //被我remark了,不remark也是可以跑的
FMatrix operator * (FMatrix &);
};

FMatrix::~FMatrix()
{
delete[] FData;
FData=NULL;
FRow=0;
FCol=0;
}
//======================================================
bool FMatrix::Set_Count(unsigned int Row,unsigned int Col)
{
if(Row <= 0 || Col <= 0) return (false);
if(Row==FRow&&Col==FCol) return (true);
FData = new double[Row*Col];
FRow = Row;
FCol = Col;
return true;
}
//======================================================
void FMatrix::Create(unsigned int Row, unsigned int Col)
{
Set_Count(Row,Col);
}
//======================================================
double __fastcall FMatrix::GetData(unsigned int Row,unsigned int Col) const
{
if (Row > 0 && Col > 0 && Row <= FRow && Col <= FCol)
return (FData[FCol*(Row-1) Col-1]);
else
return (0);
}
//======================================================
void __fastcall FMatrix::SetData(unsigned int Row,unsigned int Col,double data)
{
if (Row > 0 && Col > 0 && Row <= FRow && Col <= FCol)
FData[FCol*(Row-1) Col-1] = data;
}
//======================================================
/*
FMatrix& FMatrix::operator = (const FMatrix &Temp)
{
if(Temp.FRow ==FRow && Temp.FCol ==FCol){
for(unsigned int i=1;i<=FRow;i ){
for(unsigned int j=1;j<=FCol;j ){
Data[i][j] = Temp.Data[i][j];
}
}
}
return *this;
}
*/
//======================================================
FMatrix::FMatrix(const FMatrix &src) //這個建構子是我加入的
{
Set_Count(src.FRow,src.FCol);
for(unsigned int i=1;i<=FRow;i ){
for(unsigned int j=1;j<=FCol;j ){
Data[i][j] = src.Data[i][j];
}
}
}
//======================================================
FMatrix FMatrix::operator* (FMatrix &Temp)
{
FMatrix Result;
unsigned int col;
unsigned int row;
col = Temp.FCol;
row = FRow;
Result.Create(row,col);
for(unsigned int i=1;i<=row;i ){
for(unsigned int j=1;j<=col;j ){
Result.Data[i][j] = 0;
for(unsigned int k=1;k<=FCol;k ){
Result.Data[i][j] = Data[i][k]*Temp.Data[k][j];
}
}
}
return Result;
}
//======================================================
void __fastcall TForm1::Button1Click(TObject *Sender)
{
FMatrix A,B;
A.Create(2,2);
B.Create(2,2);
A.Data[1][1] = 1.0;
A.Data[1][2] = 2.0;
A.Data[2][1] = 3.0;
A.Data[2][2] = 4.0;
B.Data[1][1] = 1.0;
B.Data[1][2] = 1.0;
B.Data[2][1] = 1.0;
B.Data[2][2] = 1.0;
B = A * B;
}
[/code]
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2008-11-16 05:02:29, 註解 無‧
aftcast 重新編輯於 2008-11-16 05:06:11, 註解 無‧
aftcast 重新編輯於 2008-11-16 11:20:16, 註解 無‧
qqmts0726
一般會員


發表:11
回覆:6
積分:8
註冊:2008-06-27

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-11-16 13:27:16 IP:118.169.xxx.xxx 訂閱
感謝 aftcast 大大的協助:: 
讓我多上了一課...以往在做 class的時候,並不會去做 copy constructor 這項動作,但原來她的影響那麼大 ˋ ˊ
http://caterpillar.onlyfun.net/Gossip/CppGossip/CopyConstructorAndAssign.htm
系統時間:2024-05-18 20:15:27
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!