2015-11-13 27 views
2

我正在寫簡單的C++應用程序來乘以兩個矩陣。是的,我知道這個版本不會檢查例如行數是否大於零。C++ OOP - 數組(矩陣)乘法,刪除對象

我可以使用默認的構造函數創建兩個對象,並且我可以創建第三個對象(同一類的兩個先前對象相乘的結果)。然而,我不能正確刪除這第三個對象。當我嘗試時,出現「訪問違規讀取位置」異常。你能告訴我我錯過了什麼嗎?有什麼我忘記初始化?這個異常僅在使用myThirdFunction時引發。

進行此代碼更好的任何其他意見都是歡迎的。

#include <iostream> 
#include <ctime> 
#include <iomanip> 
using namespace std; 

class MyArray 
{ 
int Variable1 = 0; 
int Variable2 = 0; 
float ** myArray; 
public: 
MyArray() : Variable1(0), Variable2(0){ myFunction(); } 

MyArray (int variable1, int variable2) : Variable1(variable1): 
Variable2(variable2){ myFunction(); } 

MyArray(const MyArray &myArrayA, const MyArray &myArrayB) : 
Variable1(myArrayA.Variable1), Variable2(myArrayB.Variable2) 
{ myThirdFunction(myArrayA, myArrayB); } 

MyArray(const MyArray &myArray) 
{ Variable1=myArray.Variable1; Variable2 = myArray.Variable2; 
this->myArray =myArray.myArray; } 

void myFunction() { 
    cin >> Variable1; 
    cin >> Variable2; 
    myArray = new float*[Variable1]; 
    myOtherFunction(); 
} 

void myOtherFunction() { 
    for (int i = 0; i < Variable1; ++i) 
    { 
     myArray[i] = new float[Variable2]; 
     for (int j = 0; j < Variable2; ++j) 
      myArray[i][j] = rand() % (10 - 0) + 0; 
    }  
} 

void myThirdFunction(MyArray myArrayA, MyArray myArrayB) 
{ 
    Variable1 = myArrayA.Variable1; 
    Variable2 = myArrayB.Variable2; 
    myArray = new float*[Variable1]; 
    for (int i = 0; i < Variable1; ++i) 
    { 
     myArray[i] = new float[Variable2]; 
     for (int j = 0; j < Variable2; ++j) 
     { 
      float tempVariable = 0; 
      for (int q = 0; q < myArrayA.Variable2; ++q) 
      { 
       tempVariable += myArrayA.myArray[i][q] * myArrayB.myArray[q][j]; 
      } 
      myArray[i][j] = tempVariable; 
     } 
    } 
} 

void displayMyArray() { 
    for (int i = 0; i < Variable1; ++i) 
    { 
     for (int j = 0; j < Variable2; ++j) 
      cout << myArray[i][j] << '\t'; 
     cout << endl; 
    } 
} 

~MyArray() { 
    for (int i = 0; i < Variable1; ++i) 
    { 
     delete[] myArray[i]; 
    } 
    delete[]myArray; 
} 
}; 

int main(){ 
srand(time(0)); 
MyArray myArrayA; 
myArrayA.displayMyArray(); 
cout << endl; 
MyArray myArrayB; 
myArrayB.displayMyArray(); 
cout << endl; 
MyArray myArrayC(myArrayA, myArrayB); 

myArrayC.displayMyArray(); 

getchar(); 
getchar(); 
return 0; 
} 

謝謝:)

回答

2

成員myArray是一個指針,而在你的拷貝構造函數,你剛纔複製的指針,而無需創建新陣列。由於myThirdFunction按值取兩個參數,因此會創建原始對象的兩個副本。而且由於複製構造函數不會創建新值,所以當這兩個副本超出函數末尾的範圍時,原始指針現在指向釋放內存。只要原始的兩個對象被銷燬,析構函數就會嘗試刪除已經被刪除的內存。

從一開始,你有這樣的構造:

MyArray(const MyArray &myArrayA, const MyArray &myArrayB) 
{ 
    myThirdFunction(myArrayA, myArrayB); //This call creates two new objects 
} 

myThirdFunctionvoid myThirdFunction(MyArray myArrayA, MyArray myArrayB)的簽名,按值傳遞,並創建兩個新副本。這就爲這兩個參數調用了複製構造函數:

MyArray(const MyArray &myArray) 
{ 
    this->myArray =myArray.myArray; //shallow copy, very bad 
} 

新對象現在指向與原始文件相同的內存。所以,當它們在myThirdFunction的末尾被銷燬時,原來的指針變成垃圾。從廣泛的角度來看,這發生了。 float* p = new float; delete p; delete p;解決的辦法是使拷貝構造函數實際上覆制的元素,而不是指針:

MyArray(const MyArray &p_copy) //The name confused me so I changed it 
{ 
    Variable1 = p_copy.Variable1; 
    Variable2 = p_copy.Variable2; 
    myArray new float*[Variable1]; 
    for (int i = 0; i < Variable1; ++i) 
    { 
     myArray[i] = new float[Variable2]; 
     for (int j = 0; j < Variable2; ++j) 
      myArray[i][j] = p_copy.myArray[i][j]; 
    } 
} 

此外,你可能想通過不斷引用傳遞到myThirdFunction

void myThirdFunction(const MyArray& myArrayA, const MyArray& myArrayB) 

我看不到需要在這裏創建兩個臨時對象。

1

第一次這段代碼會起作用。

#include <iostream> 
#include <ctime> 
#include <iomanip> 
using namespace std; 

class MyArray 
{ 
    int Variable1; 
    int Variable2; 
    float ** myArray; 
public: 
    MyArray() : myArray(NULL), Variable1(0), Variable2(0) // initialize pointers with NULL is important 
    { 
     myFunction(); 
    } 

    MyArray (int variable1, int variable2) : myArray(NULL), Variable1(variable1), 
    Variable2(variable2) 
    { 
     myFunction(); 
    } 

    MyArray(const MyArray &myArrayA, const MyArray &myArrayB) : myArray(NULL), 
    Variable1(myArrayA.Variable1), Variable2(myArrayB.Variable2) 
    { 
     myThirdFunction(myArrayA, myArrayB); 
    } 

    MyArray(const MyArray &myArray) 
    { 
     Variable1=myArray.Variable1; Variable2 = myArray.Variable2; 
     this->myArray =myArray.myArray; 
    } 

    void myFunction() 
    { 
     cin >> Variable1; 
     cin >> Variable2; 
     myArray = new float*[Variable1]; 
     myOtherFunction(); 
    } 

    void myOtherFunction() 
    { 
     for (int i = 0; i < Variable1; ++i) 
     { 
      myArray[i] = new float[Variable2]; 
      for (int j = 0; j < Variable2; ++j) 
       myArray[i][j] = rand() % (10 - 0) + 0; 
     }  
    } 

    void myThirdFunction(MyArray myArrayA, MyArray myArrayB) 
    { 
      // cols of first must be same as rows of second 
     if (myArrayA.Variable2 != myArrayB.Variable1) 
      return; 

      // memory must be cleaned before new array creation 
     clearArray(); 

     Variable1 = myArrayA.Variable1; 
     Variable2 = myArrayB.Variable2; 

     myArray = new float*[Variable1]; 
     for (int i = 0; i < Variable1; ++i) 
     { 
      myArray[i] = new float[Variable2]; 
      for (int j = 0; j < Variable2; ++j) 
      { 
       float tempVariable = 0; 
       for (int q = 0; q < myArrayA.Variable2; ++q) 
       { 
        tempVariable += myArrayA.myArray[i][q] * myArrayB.myArray[q][j]; 
       } 
       myArray[i][j] = tempVariable; 
      } 
     } 
    } 

    void displayMyArray() 
    { 
     for (int i = 0; i < Variable1; ++i) 
     { 
      for (int j = 0; j < Variable2; ++j) 
       cout << myArray[i][j] << '\t'; 
      cout << endl; 
     } 
    } 

    ~MyArray() 
    { 
     clearArray(); 
    } 

    // clear memory and deinitialize pointers 
    void clearArray() 
    { 
     if (myArray == NULL) 
      return; 

     for (int i = 0; i < Variable1; ++i) 
     { 
      delete[] myArray[i]; 
      myArray[i] = NULL; 
     } 

     delete[]myArray; 
     myArray = NULL; 
    } 

}; 

int main(){ 
    srand(time(0)); 
    MyArray myArrayA; 
    myArrayA.displayMyArray(); 
    cout << endl; 
    MyArray myArrayB; 
    myArrayB.displayMyArray(); 
    cout << endl; 
    MyArray myArrayC(myArrayA, myArrayB); 

    myArrayC.displayMyArray(); 

    getchar(); 
    getchar(); 
    return 0; 
} 

但我強烈建議更換你創建正確的拷貝構造函數和賦值操作裝置(operator=),以正確的對象創建和銷燬。

在這裏,我張貼我自己的矩陣實現來引用你以什麼方式批准你的代碼。

#include <iostream.h> 
#include <conio.h> 
#include <stdlib.h> 

using namespace std:: 

class Matrix 
{ 
public: 
    Matrix(); 
    Matrix(int rowcount,int colcount); 
    Matrix(int rowcount,int colcount,float* matrix); 
    Matrix(const Matrix& rhs); 
    ~Matrix(); 
    ///////////////////////////////////////////////////////////// 
    Matrix& operator = (const Matrix& rhs); 
    Matrix operator + (const Matrix& rhs); 
    Matrix operator - (const Matrix& rhs); 
    Matrix operator * (float scale); 
    Matrix operator * (const Matrix& rhs); 
    void operator += (const Matrix& rhs); 
    void operator -= (const Matrix& rhs); 
    void operator *= (float scale); 
    void operator *= (const Matrix& rhs); 
    float operator [] (int offset) const; 
    float& operator [] (int offset); 
    friend ostream& operator << (ostream& _str,const Matrix& rhs); 
    ///////////////////////////////////////////////////////////// 
    void setCols(int cols); 
    void setRows(int rows); 
    void setMatrix(float* matrix); 
    int getCols() const 
    { 
    return itsCols; 
    } 
    int getRows() const 
    { 
    return itsRows; 
    } 
    const float* getMatrix() const 
    { 
    Invariants(); 
    return itsMatrix; 
    } 
    void Invariants() const 
    { 
     if ((!(itsCols && itsRows && itsMatrix)) && (itsRows < 0) && (itsCols < 0)) 
     { 
     cout << "Not allowed action!\n"; 
     getch(); 
     exit(0); 
     } 
    } 
    ///////////////////////////////////////////////////////////// 
private: 
    float* itsMatrix; 
    int itsRows; 
    int itsCols; 
}; 


Matrix::Matrix() 
{ 
    itsRows = 0; 
    itsCols = 0; 
    itsMatrix = NULL; 
} 

Matrix::Matrix(int rowcount,int colcount) 
{ 
    itsRows = rowcount; 
    itsCols = colcount; 
    itsMatrix = new float[itsRows * itsCols]; 
    Invariants(); 
} 

Matrix::Matrix(int rowcount,int colcount,float* matrix) 
{ 
    itsRows = rowcount; 
    itsCols = colcount; 
    itsMatrix = new float[itsCols * itsRows]; 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < itsCols; j++) 
    { 
     itsMatrix[counter] = matrix[counter]; 
     counter++; 
    } 
    } 
    Invariants(); 
} 

Matrix::Matrix(const Matrix& rhs) 
{ 
    itsCols = rhs.getCols(); 
    itsRows = rhs.getRows(); 
    itsMatrix = new float[itsRows * itsCols]; 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
     for (int j = 0; j < itsCols; j++) 
     { 
     itsMatrix[counter] = rhs[counter]; 
     counter++; 
     } 
    } 
} 

Matrix::~Matrix() 
{ 
    itsCols = 0; 
    itsRows = 0; 
    delete [] itsMatrix; 
    itsMatrix = NULL; 
} 

Matrix& Matrix::operator = (const Matrix& rhs) 
{ 
    if (&rhs == this) 
     return *this; 
    else 
    { 
     itsRows = rhs.getRows(); 
     itsCols = rhs.getCols(); 
     delete [] itsMatrix; 
     itsMatrix = NULL; 
     itsMatrix = new float[itsRows * itsCols]; 
     int counter = 0; 
     for (int i = 0; i < itsRows; i++) 
     { 
     for (int j = 0; j < itsCols; j++) 
     { 
      itsMatrix[counter] = rhs[counter]; 
      counter++; 
     } 
     } 
     return *this; 
    } 
} 

float& Matrix::operator [] (int offset) 
{ 
    Invariants(); 
    if ((offset > -1) && (offset < itsCols * itsRows)) 
     return itsMatrix[offset]; 
    else 
    { 
     cout << "You cann't reach this element!\n"; 
     getch(); 
     exit(0); 
    } 
    return itsMatrix[offset]; 
} 

float Matrix::operator [] (int offset) const 
{ 
    Invariants(); 
    if ((offset > -1) && (offset < itsCols * itsRows)) 
     return itsMatrix[offset]; 
    else 
    { 
     cout << "You cann't reach this element!\n"; 
     getch(); 
     exit(0); 
    } 
    return 0; 
} 

Matrix Matrix::operator + (const Matrix& rhs) 
{ 
    Invariants(); 
    if (!((this->itsCols == rhs.getCols()) && 
    (this->itsRows == rhs.getRows()))) 
    { 
     cout << "Cann't perform addiction of matrixes!\n"; 
     getch(); 
     exit(0); 
    } 
    Matrix temp(itsRows,itsCols); 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
     for (int j = 0; j < itsCols; j++) 
     { 
     temp[counter] = itsMatrix[counter] + rhs[counter]; 
     counter++; 
     } 
    } 
    return temp; 
} 

Matrix Matrix::operator - (const Matrix& rhs) 
{ 
    Invariants(); 
    if (!((this->itsCols == rhs.getCols()) && 
    (this->itsRows == rhs.getRows()))) 
    { 
     cout << "Cann't perform substraction of matrixes!\n"; 
     getch(); 
     exit(0); 
    } 
    Matrix temp(itsRows,itsCols); 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < itsCols; j++) 
    { 
     temp[counter] = itsMatrix[counter] - rhs[counter]; 
     counter++; 
    } 
    } 
    return temp; 
} 

Matrix Matrix::operator * (float scale) 
{ 
    Invariants(); 
    Matrix temp(itsRows,itsCols); 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < itsCols; j++) 
    { 
     temp[counter] = itsMatrix[counter] * scale; 
     counter++; 
    } 
    } 
    return temp; 
} 

Matrix Matrix::operator * (const Matrix& rhs) 
{ 
    Invariants(); 
    if (!(itsCols == rhs.getRows())) 
    { 
    cout << "Cann't perform multiplication of matrixes!\n"; 
    getch(); 
    exit(0); 
    } 
    Matrix temp(itsRows,rhs.getCols()); 
    int counter = 0; 
    float sum = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < rhs.getCols(); j++) 
    { 
     for (int k = 0; k < itsCols; k++) 
     { 
     sum += itsMatrix[i * itsCols + k] * 
     rhs[k * rhs.getCols() + j]; 
     } 
     temp[counter] = sum; 
     sum = 0; 
     counter++; 
    } 
    } 
    return temp; 
} 

void Matrix::operator += (const Matrix& rhs) 
{ 
    if (!((this->itsCols == rhs.getCols()) && 
    (this->itsRows == rhs.getRows()))) 
    { 
     cout << "Cann't perform addiction of matrixes!\n"; 
     getch(); 
     exit(0); 
    } 
    Matrix temp(itsRows,itsCols); 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
     for (int j = 0; j < itsCols; j++) 
     { 
     temp[counter] = itsMatrix[counter] + rhs[counter]; 
     counter++; 
     } 
    } 
    *this = temp; 
} 

void Matrix::operator -= (const Matrix& rhs) 
{ 
    if (!((this->itsCols == rhs.getCols()) && 
    (this->itsRows == rhs.getRows()))) 
    { 
     cout << "Cann't perform substraction of matrixes!\n"; 
     getch(); 
     exit(0); 
    } 
    Matrix temp(itsRows,itsCols); 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < itsCols; j++) 
    { 
     temp[counter] = itsMatrix[counter] - rhs[counter]; 
     counter++; 
    } 
    } 
    *this = temp; 
} 

void Matrix::operator *= (float scale) 
{ 
    Invariants(); 
    Matrix temp(itsRows,itsCols); 
    int counter = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < itsCols; j++) 
    { 
     temp[counter] = itsMatrix[counter] * scale; 
     counter++; 
    } 
    } 
    *this = temp; 
} 

void Matrix::operator *= (const Matrix& rhs) 
{ 
    Invariants(); 
    if (!(itsCols == rhs.getRows())) 
    { 
    cout << "Cann't perform multiplication of matrixes!\n"; 
    getch(); 
    exit(0); 
    } 
    Matrix temp(itsRows,rhs.getCols()); 
    int counter = 0; 
    float sum = 0; 
    for (int i = 0; i < itsRows; i++) 
    { 
    for (int j = 0; j < rhs.getCols(); j++) 
    { 
     for (int k = 0; k < itsCols; k++) 
     { 
     sum += itsMatrix[i * itsCols + k] * 
     rhs[k * rhs.getCols() + j]; 
     } 
     temp[counter] = sum; 
     sum = 0; 
     counter++; 
    } 
    } 
    *this = temp; 
} 

ostream& operator << (ostream& _str,const Matrix& rhs) 
{ 
    rhs.Invariants(); 
    int counter = 0; 
    for (int i = 0; i < rhs.getRows(); i++) 
    { 
    for (int j = 0; j < rhs.getCols(); j++) 
    { 
     _str << rhs[counter] << "\t"; 
     counter++; 
    } 
    _str << endl; 
    } 
    return _str; 
} 

float arr1[] = 
{ 
    2, 2, 2, 
    -1, -3, -5, 
    16, 8, 24, 
    8, 0, 16 
}; 

float arr2[] = 
{ 
    15, 
    2, 
    -4 
}; 

int main() 
{ 
    clrscr(); 
    Matrix m1(4,3,arr1); 
    Matrix m2(3,1,arr2); 
    cout << "Matrix 1:\n"; 
    cout << m1 << endl; 
    cout << "Matrix 2:\n"; 
    cout << m2 << endl; 
    cout << "Matrix 1 * Matrix 2\n"; 
    cout << m1 * m2 << endl; 
    getch(); 
    cout << "Matrix 1 + Matrix 1\n"; 
    cout << m1 + m1 << endl; 
    getch(); 
    cout << "Matrix 1 - Matrix 1\n"; 
    cout << m1 - m1 << endl; 
    getch(); 
    cout << "Matrix 1 * 4\n"; 
    cout << m1 * 4 << endl; 
    getch(); 
    return 0; 
} 
+0

@使用方法:我給你提供了有用的答案嗎? – Mykola

+0

是的,謝謝:)你的回答非常有幫助。 James Root先生也向我解釋了我的拷貝構造函數出了什麼問題,所以現在一切都很完美:) – Deuces