Matrix Operator 乘法的問題 |
答題得分者是:aftcast
|
qqmts0726
一般會員 發表:11 回覆:6 積分:8 註冊:2008-06-27 發送簡訊給我 |
各位大大您好::
小弟最近正在練習撰寫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 發送簡訊給我 |
|
qqmts0726
一般會員 發表:11 回覆:6 積分:8 註冊:2008-06-27 發送簡訊給我 |
先感謝大大您的回覆::
在我的測試中 [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 發送簡訊給我 |
我也測了好久,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 |
qqmts0726
一般會員 發表:11 回覆:6 積分:8 註冊:2008-06-27 發送簡訊給我 |
感謝 aftcast 大大的協助::
讓我多上了一課...以往在做 class的時候,並不會去做 copy constructor 這項動作,但原來她的影響那麼大 ˋ ˊ http://caterpillar.onlyfun.net/Gossip/CppGossip/CopyConstructorAndAssign.htm |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |