2014-12-01 1 views
0

저는 복사 생성자로 소멸자를 사용하는 개념에 정말로 고심하고 있습니다. 소멸자를 사용하지 않으면 코드가 자동으로 작동하므로 잘 작동합니다. 만약 그렇다면 'Debug Assertion Failed!'라는 오류 메시지가 나타납니다. 및 '표현식 : _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse).소멸자가 프로그램을 크래시시킵니다.

하지만 소멸자 사용법을 이해하고 싶습니다. 아래에 코드가 있습니다. 내가 잘못했거나해야 할 일을 설명하는 데 도움을 주셔서 감사합니다!
클래스 매트릭스 {복사 - 생성자에서

private: 
    int M; 
    int N; 
    double *data; 

public: 
    Matrix(); 
    int getM() const { return M; } 
    int getN() const { return N; } 

    //CONSTRUCTOR 
    Matrix(int sizeR, int sizeC,double * input_data) 
    { 
     M = sizeR; //Rows 
     N = sizeC; //Columns 

     data = new double[M*N]; //creation of 1D array, uses m&n values 

     cout << "\nMatrix::Matrix(int sizeR, int sizeC, double * data_value) is invoked...\n\n"; 

     //ENTER DATA INTO MATRIX HERE: 
     for(int i=0; i < M*N; i++) //Loops for every data entry into 1D array, uses r&c as referenece to 
      data[i] = input_data[i];//Accesses each value at specific location, inputs value 'val' 
     for(int i = 0; i < M*N; i++) //Loops for every data entry into 1D array, uses r&c as referenece to size 
      cout << data[i] << " "; 
    } 

    //get function uses row and column from user 
    double get(int i, int j) 
    { 
     return data[i*N+j]; 
    } 

    double set(int i, int j, double val) 
    { 
     data[i*N+j] = val; 

     cout << "\n\nNEW MATRIX: "; 
     for(int i = 0; i < M*N; i++)//Loops for every data entry into 1D array, uses r&c as referenece to size 
      cout << data[i] << " "; 

     return val; 
    } 

    Matrix(const Matrix& oldMatrix) 
    { 
     cout¸<< "\nMatrix::Matrix(const Matrix&) is invoked...."; 
     M = oldMatrix.getM(); 
     N = oldMatrix.getN(); 
     data = oldMatrix.data; 

     cout << "\n\n"; 

     //ENTER DATA INTO MATRIX HERE: 

     for(int i = 0; i < M*N; i++)//Loops for every data entry into 1D array, uses r&c as referenece to size 
      cout << data[i] << " "; 

    } 

    //DESTRUCTOR 
    ~Matrix() 
    { 
     //delete data 
     delete [] data; 
     data = NULL; 
     cout << "\n\nMatrix::~Matrix() is invoked...\n\n"; 
    } 



}; 

int main() 
{ 
    int sizeR, sizeC; 
    double val; 

    cout << "Enter No. Rows: "; 
    cin >> sizeR; 

    cout << "Enter No. Columns: "; 
    cin >> sizeC; 

    double * input_data; 


    input_data = new double[sizeR*sizeC]; 

    //INPUTS VALUES TO ARRAY 
    for(int i = 0; i < sizeR*sizeC; i++)//Loops for every row 
     input_data[i] = i; 

    Matrix M1(sizeR, sizeC, input_data); 

    cout << "Enter row that value you are after is in: "; 
    cin >> sizeR; 
    cout << " & now the column that it is in: "; 
    cin >> sizeC; 


    cout << "Change value: " << M1.get(sizeR, sizeC) << " to:"; 
    cin >> val; 
    M1.set(sizeR, sizeC, val); 

    //calls copy constructor 
    M1 = Matrix(M1); 
} 
+1

'new []'가 몇 번이나 호출 되었습니까? 'delete []'가 몇 번 호출 되는가? –

+0

copy-constructor에서'data = oldMatrix.data1'을 설정하면 매우 의심스러워 보입니다 !!! –

+0

참고 자료, 그것은 * deconstructor *가 아니라 * 소멸자 *입니다. 나는 또한 당신의 코드를 들여 쓰고 엉성하게 만들었다. 공백을 두려워하지 마십시오. – jrok

답변

4

당신은 당신이 지금 두 개체 같은 포인터를 가지고 모두가 당신을 의미 포인터를 복사합니다. 이러한 객체 중 하나가 파괴되면 다른 객체에 현재 유효하지 않은 포인터가 남습니다.

어쨌든이 포인터를 역 참조하거나 해방하려고 시도하면 undefined behavior이됩니다.

M1 = Matrix(M1); 

그 라인이 일시적으로 객체를 생성, 복사는 임시 개체에 M1의 데이터는, 그것은 (M1 다시 임시 객체를 할당합니다

문제의 문제 라인

이 하나입니다 컴파일러에서 생성 한 복사 할당 연산자는 복사 생성자와 크게 다르지 않은 멤버의 단순 복사본을 수행 한 다음 임시 객체를 소멸시켜 표류 및 유효하지 않은 포인터를 M1으로 유도합니다. 약간 관련 문제에


은 또한에 대한 the rule of three을 배울 수도 있습니다.

+2

제로의 규칙을 제안 할 수도 있습니다 – sp2danny

0

당신은 복사 생성자 안에 다른에 하나의 객체의 포인터를 복사 : 동일한 memoryblock 참조 두 개체가

Matrix(const Matrix& oldMatrix) 
{ 
    ... 
    data = oldMatrix.data; 

복사 생성자를 호출 한 후. 그리고 한 개체가 파괴되면 메모리 블록이 삭제되고 두 번째 개체가 잘못된 메모리 위치를 가리 킵니다.

복사 생성자에서 새 버퍼를 할당해야합니다!

-2

솔루션은 Matrix 클래스에 bool 변수 (예 : is_copy)를 추가 할 수 있습니다. 생성자에서는 false로 설정하고 복사 생성자에서는 true로 설정하십시오. is_copy가 false 인 경우에만 소멸자에서 메모리를 할당 해제하십시오.

또는 의견에 제안 된대로 스마트 포인터를 사용하는 것이 좋습니다.

+3

이것은 해결책이 아니며 단지 더 많은 문제를 추가합니다. 첫 번째 객체가 파괴되었지만 사본이 여전히 존재한다면? boolean 플래그를 사용하여 소유권 및 간접 참조 문제를 해결할 수 없습니다. –

+0

그게 내가 "될 수있다"고 말한 이유입니다.얕은 복사본을 만들고 싶지 않고 단순히 참조로 행렬을 전달하지 못할 때가 있습니다. 원래 객체가 프로그램의 전체 실행에서 생존하려고한다면 아무 문제가 없습니다. – Noel

+0

@NoelPerezGonzalez @WojtekSurowka가 말했듯이, 스마트 포인터가 이것을 해결할 것입니다. 부울은 그것을 해결하지 못합니다. 'std :: shared_ptr' 또는'boost :: shared_ptr'를 사용하십시오. 그러나 데이터가 'const'일 때만이 공유 접근 방식을 사용합니다. – tillaert

관련 문제