C++ 메모리해제 Debug Assertion

조회수 12221회
#include <iostream>
#include <fstream>
//http://is03.tistory.com/3 HOW to use eof

using namespace std;
#define FILENAME "data.txt"
ifstream fin;

class Matrix {

private:
    int size;
    int numOfNonZero;
    int* row;
    int* col;
    int* value;

public:
    Matrix(); // constructor
    Matrix(const Matrix&); // copy constructor
    ~Matrix();
    void display();
    void getData();
    Matrix operator*(const Matrix&);
};
Matrix::Matrix() {

}
void Matrix::getData() {

    fin >> this->size;
    fin >> this->numOfNonZero;
    row = new int[numOfNonZero];
    col = new int[numOfNonZero];
    value = new int[numOfNonZero];

    for (int i = 0; i < numOfNonZero; i++) {
        fin >> row[i] >> col[i] >> value[i];
    }
}
Matrix Matrix::operator*(const Matrix& rhs) {
    Matrix ans;
    return ans;
}
void Matrix::display() {
    cout << "The Matrix is : " << endl;
    for (int i = 0; i < this->numOfNonZero; i++) {
        cout << row[i] << " " << col[i] << " " << value[i] << endl;
    }

}

Matrix::~Matrix() {
    if (this->row != NULL) {
        delete[] this->row;
        delete[] this->col;
        delete[] this->value;
    }
}

Matrix::Matrix(const Matrix& rhs) {
    this->size = rhs.size;
    this->numOfNonZero = rhs.numOfNonZero;

    this->row = new int(numOfNonZero);
    this->col = new int(numOfNonZero);
    this->value = new int(numOfNonZero);

    for (int i = 0; i < numOfNonZero; i++) {
        this->row[i] = rhs.row[i];
        this->col[i] = rhs.col[i];
        this->value[i] = rhs.value[i];
    }

}

int main() {
    fin.open(FILENAME);

    Matrix A, B, C;
    A.getData();
    B.getData();
    A.display(); B.display();

    C = A * B;

    return 0;
}

Visual Studio에서 실행하면 Debug Assertion이 발생하더라구요.. 자세한 오류명은 _CrtIsValidHeapPointer(block)입니다. 디버깅 하면서 어디서 오류가 발생하는지 보니, 소멸자의 delete에서 발생하더라구요. 왜 이런 오류가 발생하는 지 잘 모르겠습니다.

  1. 왜 이런 오류가 발생하나요?
  2. 그리고 _CrtIsValidHeapPointer(block) 이 오류가 어떤 오류를 나타내는지 궁금합니다.

ps. 메인에서,
Matrix C; C = A * B; 가 아니라, Matrix C = A * B;

이렇게 하면 또 오류가 발생안하는 군요..;;

설명점 해주시면 감사하겠습니다..!!!

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • 일단, ps에 적으신 두 코드는 같은 코드가 아닙니다.

    Matrix C;    // 객체가 생성되면서 기본 생성자 호출됨
    C = A * B;   // 복사 대입 연산자가 호출됨
    
    Matrix C = A * B;    // 객체가 생성되면서 복사 생성자가 호출됨
    

    복사 대입 연산자는 이미 생성된 객체에 다른 객체의 값을 대입시킬 때 호출되는 것이고, 복사 생성자는 말 그대로 생성자이기 때문에 객체가 생성되는 시점에 대입되는 인자가 존재하면, 기본 생성자 대신에 호출되는 녀석입니다.

    복사 대입 연산자는 복사 생성자와 마찬가지로 직접 정의하지 않으면 컴파일러가 자동으로 생성해주는 함수입니다.

    이제 질문으로 넘어가겠습니다.


    왜 이런 오류가 발생하나요?

    코드를 보니, 복사 생성자를 직접 정의하셨는데, 인자로 전달된 객체의 멤버 변수를 nullptr 체크 없이 사용하고 있습니다.

    for (int i = 0; i < numOfNonZero; i++) {
        this->row[i] = rhs.row[i]; // 포인터 변수를 참조하고 있다.
        this->col[i] = rhs.col[i];
        this->value[i] = rhs.value[i];
    }
    

    해당 복사 생성자가 호출되는 코드를 보니, A * B 를 통해 반환되는 객체를 인자로 넘깁니다.

    C = A * B; // C의 복사 생성자가 호출되는 시점
    

    A * B 연산은 연산자 오버로딩이 아래와 같이 되어 있습니다. (이 부분은 아직 구현이 덜 된 것으로 보입니다.)

    Matrix Matrix::operator*(const Matrix& rhs) {
        Matrix ans;
        return ans; // 그냥 새로운 객체를 하나 생성해서 반환...
    }
    

    Matrix 클래스의 멤버 포인터 변수들(row 등)은 기본 생성자에서 값을 할당하지 않고, getData() 함수를 통해서 값을 할당하도록 되어 있습니다.

    따라서, 결과적으로 C의 복사 생성자에 인자로 전달되는 인스턴스는 할당되지 않은 포인터 변수들을 가지고 있고, 이를 사용하려고 했기 때문에 오류가 발생한 것입니다.


    그리고 _CrtIsValidHeapPointer(block) 이 오류가 어떤 오류를 나타내는지 궁금합니다.

    잘못된 포인터를 참조할 때 발생합니다. IsValidHeapPointer라는 어썰트는 말 그대로 해당 포인터가 valid(유효)한지 체크하는 겁니다.

    여기서 말 하는 힙(Heap)은 현재 실행 중인 프로그램의 로컬 힙 메모리를 가리키는 것으로, 즉, 해당 포인터가 참조하는 메모리 주소가 프로그램 상에서 new 등으로 할당한 공간의 주소인지를 체크하는 것입니다.

    • 답변감사합니다!! 하나 여쭤볼게 있는데, nullptr검사는 포인터 != NULL 이런식으로 하면되나요? 알 수 없는 사용자 2016.10.1 18:04
    • != NULL 등의 코드들은 옛날 방식입니다. C++11 (2011년에 지정된 C++표준) 이 적용된 최신 컴파일러들은 nullptr 이라는 키워드를 지원합니다. 즉, if (ptr != nullptr) 이렇게 검사해주시면 됩니다. 여기에 상세한 설명은 좀 그러니, 일단 왠만하면 포인터의 널체크에는 nullptr 키워드를 사용하는 게 좋다는 것만 알아두시면 될 듯 합니다. Subin Park 2016.10.1 21:01

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)