2013-04-25 52 views
2

我有一個對象,它是一類接口在GNU科學圖書館C++與函數調用奇怪的行爲通過值

typedef double real_t; 
typedef unsigned short index_t; 
class matrix 
{ 
     gsl_matrix* m; 
    public: 
     matrix(index_t rows, index_t columns, real_t val); 
} 

matrix::matrix(index_t rows, index_t columns, real_t val) 
{ 
    m=gsl_matrix_alloc(rows,columns); 
    gsl_matrix_set_all(m, val); 
    return; 
} 

index_t matrix::rows(void) 
{ 
    return m->size1; 
} 

index_t matrix::columns(void) 
{ 
    return m->size2; 
} 

發現問題的矩陣結構是,如果我用一個函數以矩陣對象通過這樣的一個值:

void test_function(const matrix m){}; 

,並用它在程序中像這樣的

int main() 
{ 
    matrix m(4,4,1); 
    cout << m.rows() << '\t' << m.columns() << endl; 
    test_function(m); 
    cout << m.rows() << '\t' << m.columns() << endl; 
} 

我蘇令人驚訝的是,即使我將const關鍵字放在參數之前,並且通過值調用,矩陣對象m的行數也被函數test_function修改爲垃圾值。 但奇怪的是,如果我使用一個功能,通過這樣的一個參考利用呼叫:

void test_function(const matrix &m){}; 

什麼也沒有發生,一切似乎就可以了吧。

據我所知,通過值調用不應該能夠修改函數的參數,特別是如果函數在這種情況下什麼也不做,特別是如果我明確地在參數名稱之前使用關鍵字const在功能原型...

任何幫助將不勝感激。

編輯:

我還定義了複製構造矩陣類作爲

matrix& matrix::operator= (const matrix& src) 
{ 
    gsl_matrix_memcpy(m,src.m); 
    return *this; 
} 

它執行gsl_matrix結構

EDIT的完整副本(I猜):

好吧,我想我終於明白了:通過value函數調用會創建一個淺拷貝對象,它只包含指向真實對象的指針,當test_fun ction終止了所有局部變量的銷燬,所以調用了矩陣類的析構函數(爲了簡潔起見這裏定義但省略),但是這樣main函數中的對象(局部m指向的是)與局部變量一起銷燬..無論如何,我解決了定義一個合適的拷貝構造函數的問題,該構造函數執行對象的完整(深層)副本,然後使用引用調用,這對於大量計算應該更好。非常感謝大家的幫助!

+1

你的'matrix'構造函數有3個參數但是你用4創建'm'是怎麼回事? – 2013-04-25 08:25:13

+1

通過值傳遞參數調用複製構造函數,它可以執行任何操作。 – Elazar 2013-04-25 08:26:00

+0

給Alexey Frunze:你說得對,那是因爲在我的真實程序中,還有一個帶有4個參數的構造函數,它將矩陣初始化爲最後兩個參數之間的隨機值,現在我改變了它 – woggio 2013-04-25 09:07:33

回答

1

當您通過值傳遞參數時,編譯器會調用單參數副本構造函數以在該函數中創建值。如果您不提供複製構造函數,編譯器會爲您生成一個。

在上面的例子中,編譯器生成的拷貝構造函數使內部矩陣指針的淺拷貝。當函數中新生成的矩陣超出範圍時,淺拷貝的指針也會被刪除。我的猜測是這是原因。

你可以通過提供一個不復制gsl_matrix指針的拷貝構造函數來檢查它。

+0

我試過改變你指定的拷貝構造函數,但沒有任何改變,無論如何,我不明白如何改變main中的原始對象,因爲即使函數中的局部指針變量丟失了,原始指針mm也應該保持不變 – woggio 2013-04-25 09:25:04

+0

正如MadKeithV指出的那樣,我沒有使用標準的拷貝構造函數,現在它可以工作,但我仍然不明白原始對象怎麼可能被修改,因爲函數test_function真的什麼都不做,無論如何感謝您的幫助! – woggio 2013-04-25 10:11:27

+0

@ user2318607刪除臨時指針時釋放內存。該內存然後被程序重用以用於其他事情。你原來的指針仍然指向這個內存被用於其他的東西,所以你看到的變化。遵循三條規則http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29注意一些編譯器在調試版本中寫入了釋放內存,以使這種類型的錯誤更容易檢測,所以它通常不會不要緊,你沒有做任何事情。 – stonemetal 2013-04-25 13:46:36

2

因爲默認拷貝ctor只是生成一個淺拷貝,也就是說,它只拷貝指針m的值,而不是分配一個新拷貝。

+0

謝謝,因爲我不知道複製ctor是通過值調用函數調用的,但實際上在我的代碼中我定義了一個拷貝構造函數,因爲我認爲它不重要,所以我省略了,現在我編輯 – woggio 2013-04-25 09:19:33