2013-04-02 104 views
0

我有一個類似矩陣的類。 所以用例是一樣的東西:矩陣類的深層副本

Matrix matrix(10,10); 
matrix[0][0]=4; 
//set the values for the rest of the matrix 
cout<<matrix[1][2]<<endl; 

代碼:

#include <iostream> 
#include <cstdlib> 
#include <cstdio> 
#include <cstring> 
#include <sstream> 

using namespace std; 

class Matrix { 
public: 


    Matrix(int x, int y); 

    class Proxy { 
    public: 

     Proxy(int* _array) : _array(_array) { 
     } 

     int &operator[](int index) const { 
      return _array[index]; 
     } 
    private: 
     int* _array; 
    }; 

    Proxy operator[](int index) const { 
     return Proxy(_arrayofarrays[index]); 
    } 
    Proxy operator[](int index) { 
     return Proxy(_arrayofarrays[index]); 
    } 

    const Matrix& operator=(const Matrix& othersales); 

private: 
    int** _arrayofarrays; 
    int x, y; 
}; 

Matrix::Matrix(int x, int y) { 
    _arrayofarrays = new int*[x]; 
    for (int i = 0; i < x; ++i) 
     _arrayofarrays[i] = new int[y]; 
} 

const Matrix& Matrix::operator=(const Matrix& othermatrix) { 
    new (this) Matrix(x, y); 
    for (int i = 0; i < 3; i++) 
     for (int j = 0; j < 3; j++) 
      _arrayofarrays[i][j] = othermatrix._arrayofarrays[i][j]; 

    return *this; 
} 

int main() { 

    Matrix a(2, 3); 
    a[0][0] = 1; 
    a[0][1] = 2; 
    a[0][2] = 3; 
    a[1][0] = 4; 
    a[1][1] = 5; 
    a[1][2] = 6; 

    cout << a[1][2] << endl; 
    //prints out 6 


    const Matrix b = a; 
    cout << b[1][2] << endl; 

    a[1][2] = 3; 

    cout << a[1][2] << endl; 
    // prints out 3 
    cout << b[1][2] << endl; 
    // prints out 3 as well 
} 

通過調用const Matrix b = a;我想創建一個矩陣的新實例,將具有相同的值a在那一刻。儘管如此,b正在通過更改a中的值而受到影響。所以,如果我在a中更改某個值,那麼它也會在b中更改。我不希望它的行爲如此。

所以我需要創建一個b的副本,它不會受到a本身的影響。

這些可能是愚蠢的問題,但對我來說,作爲一個Java的傢伙和C++新手都是那些東西真的很混亂,所以感謝任何有益的建議......

+2

再次檢查[您最後一個問題的答案](http://stackoverflow.com/a/15753838/16287)。對於const對象,您需要'operator [](int index)'對於非const對象***和***'operator [](int index)const'。你只有一個。 –

+0

你不能聲明一個對象爲常量 –

+0

@DrewDormann你是對的,我忘了實現這一點。我將編輯我的帖子。儘管如此,價值仍受到原始對象變化的影響。 – Dworza

回答

1

有您的實施的幾個問題。最簡單的就是你得到的錯誤...

在你的Matrix類中,operator[]是一個非const成員函數,這意味着它只能在非const對象上執行。您的operator=const &佔據右側對象,因此您不能在其上調用operator[]。這裏的問題是,你沒有提供一個承諾不修改對象的實現operator[],一旦你添加到你的類型它應該編譯。

比這更重要的是你正在泄漏記憶。當您在對象上調用operator=時,您將創建不同的Matrix,而無需事先釋放其保存的內存。這是內存泄漏。

operator=的執行也不是線程安全的。如果爲任何內部數組分配內存失敗並拋出異常,則將使對象處於既不是原始狀態又不是有效狀態的狀態。這本身就不好。

涉及之前,儘可能多的爲修正一個可能導致其他的,你的operator=實現並不安全,如果有走樣,也就是說,它失敗如果你自己分配。第一行將泄漏內存並創建新的緩衝區,並從那裏開始將新緩衝區複製到自身中,從而丟失原始信息。

最後,如果您放棄使用operator[]的要求,而是將operator()用於這兩個索引,則可以改進此類型的實施。用戶代碼必須適應(看起來不像二維數組),但它提供了更多的表示自由(可以以任何您想要的方式在內部存儲信息)。同時,不需要分配指針數組,然後再分配N個數組int。您可以執行NxM ints的單個內存分配,並執行指針算術以解決每個位置(這與使用operator[]/operator()無關),這將減少內存佔用量並使佈局更緊湊,從而提高緩存性能(而不是提及將動態分配的數量減少M)

通過調用const Matrix b = a;我想創建Matrix的新實例,它將具有相同的a值。儘管如此,b正在通過改變a中的值而受到影響。

那麼,這是我在第一次閱讀中錯過的另一個問題。表達式const Matrix b = a;不涉及operator=,而是複製構造函數。谷歌的另一件事:規則三(基本上,如果你手動實現複製構造函數,賦值或析構函數之一,你可能想要實現所有這三個)。在沒有定義自己的拷貝構造函數的情況下,編譯器會爲你隱式地定義一個做淺拷貝的拷貝(即複製存儲在Matrix中但不爲其分配內存的指針)。複製完成後Matrix共享相同的內存,並且如果您的析構函數釋放內存,則當第二個析構函數運行並嘗試delete []已刪除的內存時,將運行到未定義行爲。

+0

感謝您的回覆,讓我解釋一下,我爲什麼按照自己的方式實施它。 1)我編輯了我的帖子,以便能夠處理'const'對象。 2)不打算複製並丟棄原文而不破壞它。它應該正常工作'=',即'int a,b;一個= 3; b = a;'~~~>'b == 3' ...下一個'a = 4;'但仍然是'b == 3',如果您知道,我的意思是。 3)我不能使用'()',因爲我試圖解決我的作業,我們必須使用'[] []'索引。 – Dworza

+1

@Dworza:re。 2)我從不假定任何人都打算泄漏記憶,或者在不同的條件下讓自己的任務變得不安全(自我賦值,例外),但是在這兩種情況下,班上的實施並不安全,它會泄漏內存。順便說一句,解決這兩個問題的常見成語是* copy-and-swap *(google it)。關於內存佈局的評論也是站得住腳的,不管你的接口使用'operator()'還是'operator []',你仍然可以用不同的方式管理內存。 –

+0

@Dworza:更新瞭解釋你爲什麼看到這種行爲的原因。您需要實現複製構造函數。 –