關於運算子+的觀念問題

Matrix operator + (const Matrix&)const;

上面是h檔部份

Matrix Matrix::operator + (const Matrix &x) const

{

static Matrix temp(Row, Col);

if(Row!=x.Row||Col!=x.Col)

{

return *this;

}

else

{

delete [] temp.data;

temp.Row = Row;

temp.Col = Col;

temp.data = new MTYPE[temp.Row*temp.Col];

temp=0;

for(i=0;i<(x.Row*x.Col);i++)//

{

temp.data[i]=data[i]+x.data[i];

}

}

return temp;

}

這是我寫的+的運算

但我想改成

const Matrix &operator + (const Matrix&);

const Matrix &Matrix::operator + (const Matrix &x)

{

static Matrix temp(Row, Col);

if(Row!=x.Row||Col!=x.Col)

{

return *this;

}

else

{

delete [] temp.data;

temp.Row = Row;

temp.Col = Col;

temp.data = new MTYPE[temp.Row*temp.Col];

temp=0;

for(i=0;i<(x.Row*x.Col);i++)//

{

temp.data[i]=data[i]+x.data[i];

}

}

return temp;

}

卻說有問題,請問是哪裡出錯?

我想問ㄧ下,(const Matrix&)是傳參考值,如果寫成(const Matrix),使用傳值可以嗎?是速度會變慢嗎?

Update:

這是作業,但程式碼是自己寫的

我一直搞不懂,在Matrix的運算中,已經有寫operator=的程式碼,為何還要寫copy constructor呢?

Update 2:

(const Matrix&)為何裡面要寫const?

我看了很多書,例子都這樣寫,但我不懂為什麼?

Update 3:

#include

using std::cout;

using std::endl;

using std::cin;

#include

using std::setw;

using std::setfill;

#include "hw12.h"

int i=0,j=0,k=0;

Update 4:

int Matrix::a=0;

int Matrix::b=0;

void Matrix::displayCounters()

{

cout<<"copy constructer= "<<<" times,assignment operator= "<<<" times."<

Update 5:

void Matrix::display()

{

for(i=0;i

Update 6:

http://140.122.185.90/c/PHP/User/s68175/2008.06.11...

這是我寫的code,因為知識都把補充的code吃掉,只好這樣連結

2 Answers

Rating
  • novus
    Lv 6
    1 decade ago
    Favorite Answer

    語法錯誤容易改,但設計問題影響很大,這個程式有許多設計上的毛病。

    1.const Matrix &Matrix::operator+(const Matrix &x)

    這就是一個不合理的operator設計。我想你已經知道這個函數不可傳回local variable和new配置出來的東西,這或許是你用static的原因。可惜static也是行不通的

    舉例來說,假如你有順便定義operator==的話,可能很快就會發現

    if ((a+b) == (c+d))

    永遠成立,因為前後兩個加算式的結果永遠參照到同一個物件,這是最顯然的case。其他還有很多很可怕的事,你會常常發現某些運算式得不到正確結果,調整一下順序忽然又正確了,有些bug永遠抓不到......

    2.傳回value type才是正確的

    const Matrix Matrix::operator+(const Matrix &x) /*可以考慮這裏加const*/ {

    Matrix temp;

    // ...do something...

    return temp;

    }

    不過你必須正確定義copy constructor和operator=,否則compiler預設的行為只會複製「指向資料的指標」,而不會複製動態配置出來的記憶體,當區域變數temp壽終正寢,將自己配置的記憶體釋放後,計算結果只會剩下一個不知指向何物的指標(我這裡假設你已經有一個稱職的destructor)。或許你會想將temp設為static,這樣動態配置的資料就不會隨函數而逝,也不用費心去撰寫copy constructor和operator=。我必須說這是個不智的做法,因為它的行為甚至比傳回參照更糟糕,前述的問題在這裡都會發生,而且更不容易察覺。

    3.但.....這樣效能不是比較差嗎?

    沒錯,速度的確會慢一點,但是至少幫您省下許多debug的時間。若你非常在意速度的話,解決的辦法之一是利用refernce counting,在Matrix解構時先檢查data所指向的陣列是否還被其他人引用,若無人使用才delete陣列,若還有其他人使用就不delete陣列。總之最後使用的人要負責歸還,不必每次都要將整個陣列複製,這樣效能和return reference或pointer幾乎一樣快。

    4.更高段的矩陣運算設計,常會採用一些lazy calculation、copy on demand(自己去google看看吧),概念有點類似上面的reference counting,只有在非不得已的時候才真正把答案算出來,達到更高的效能。

    2008-06-10 17:49:56 補充:

    note 1:如果函數的結果放在一個新物件回傳,就一定不可回傳reference type,必定要回傳value type。這不只針對operator,也針對所有函數。

    note 2:operator的行為盡可能和內建的型別一樣,尤其你正在設計數學運算程式。若是operator和內建的運算子行為有落差,就不應該設計為operator形式,應寫成一般函數以免誤用。

    note 3:如果這不是作業的話,建議您可以採用boost程式庫的線性代數功能

    http://www.boost.org/

    2008-06-11 12:14:48 補充:

    無意間發現喵大曾經回答過這題,看來是作業

    http://tw.knowledge.yahoo.com/question/question?qi...

    你原本想知道的問題大概喵大都有詳解

    只是我很好奇code是老師給的嗎?

    喵大和我花了很長篇幅指出這個程式的問題,事實上我沒講的還很多,懶得說了。

    莫非又是一個外行人教外行人的血腥慘案?

    2008-06-11 23:32:59 補充:

    operator=只負責明確出現"="符號的地方

    其餘還不那麼明顯的複製動作都是copy constructor的工作

    最常見的就是建立臨時物件

    void f(const Matrix& x)

    這裡的const表示x在函數f裡面唯讀,不可修改x所參照的原始資料。加const常常可以在編譯期就幫你找到寫壞的程式碼

    2008-06-16 22:29:13 補充:

    有些時候copy和=用compiler預設的會比手工寫快

    一項判斷的原則就是

    destruct

    copy construct

    operator=

    如果有必要寫到其中任何一個,就表示這個class三者都需要手工撰寫,即使目前的code還沒用到。

  • SiYu
    Lv 5
    1 decade ago

    你的程式中有一個 temp=0;

    0 不是Matrix . 如妳沒有寫 Matrix::operator=(int ) 這個function 在此就會有compiler error.

    2008-06-10 11:52:48 補充:

    令外你的程式有寫copy construct 嗎?

    有寫 Matrix& Matrix::operator=(const Matrix& ) 嗎 ?

    如沒有. 程式跑的過成也會出錯

    2008-06-16 11:48:26 補充:

    在Matrix的運算中,已經有寫operator=的程式碼,為何還要寫copy constructor呢?

    1.因為傳參數使用call by value 時會建立附本. 此時會透過copy construct 來建立object

    2. 回傳資料不是reference 時. c++ 也會透過copy construct 把資料建立在stack 上.在return 回去.

    但有的 compiler 真對此點有作最佳化動作. 所以return 時不一定會用到copy constructor.

    2008-06-16 11:52:47 補充:

    你自己寫的class 如要能合乎很大部份的operator .

    下幾個member 幾乎一定要寫

    1. default construct (就是沒傳參數的 construct)

    2. destruct

    3. copy construct

    4. operator=

    以上4個是最基本的.

Still have questions? Get your answers by asking now.