[c++] 메모리 중복 해제

wangki·2025년 5월 24일
0

cpp

목록 보기
2/7

개요

개발을 하던 중 crash가 발생 해 프로그램이 죽는 현상이 지속되어 문제를 해결한 방법에 대해 포스팅을 하겠다.

복사 생성자와 딥 카피에 대해 다루도록 하겠다.

내용

a라는 객체를 생성하여 글로벌 변수에서 가지고 있어야 하는 상황이었다.
글로벌 변수는 포인터로 정의가 되어있었고, a라는 객체는 내부적으로 포인터 필드를 여러 개 가지고 있는 상황이었다.
로직에서 글로벌 변수를 복사 생성자의 매개변수로 넘겨준 뒤 메모리 해제를 하였는데 프로그램이 죽는 현상이 있었다. 디버깅을 하며 문제를 찾았는데 복사 생성과정에서 특정 필드가 얕은 복사되었다. 이 후 메모리 해제 과정에서 이중 메모리 해제가 발생하여 프로그램이 정상 종료되지 않았던 것이다.

예시를 들어보겠다.

class Test {
public: 
    int* p_num = nullptr;

    Test(int* p) {
        p_num = p;
    }

    Test(const Test& other) {
        this->p_num = other.p_num;
    }

    ~Test() {
        if (p_num != NULL)
            delete p_num;
    }
};

Test 클래스에는 복사 생성자가 존재한다. p_num 포인터에 매개변수로 받은 other의 포인터 변수의 값을 넘겨준다.

    int* a = new int(10);
    Test* test1 = new Test(a);
    Test* test2 = new Test(*test1);

    std::cout << test1->p_num << std::endl;
    std::cout << test2->p_num << std::endl;

test1test2는 동일한 값을 가리키는 걸 볼 수 있다.

여기서 test1의 메모리를 해제하게 되면 test2의 포인터 필드가 가리키는 값이 존재하지 않게 되는 문제가 발생하게 된다. 이것이 얕은 복사이다.

위 사진을 보면 test1->p_numtest2->p_num이 가르키는 주소값이 같다는 걸 확인할 수 있다.

test1을 메모리 해제하게 되면 0xddddddd~~와 같은 주소로 변경이 된다.
그러나 test2->p_num이 가리키는 주솟값은 여전히 동일하다. 그러나 내부 값은 -57662307로 쓰레기로 변한다.
이것으로 보아 얕은 복사의 경우 단순히 주솟값을 넘기기 때문에 가리키는 메모리가 해제된 것을 알 수 없는 것 같다. 이 상태에서 test2를 메모리 해제시키면 에러가 발생하게 되는 것이다.

딥카피를 하기 위해서는 아래와 같이 복사 생성자를 작성해야한다.

    Test(const Test& other) {
        this->p_num = new int(*other.p_num);
    }

이렇게 하면 새로운 객체를 힙에 할당하기에 메모리 해제 시 서로에게 영향을 주지 않는다.

결론

위 예제 코드들은 간단하기 때문에 쉽게 에러를 찾을 수 있는데
코드가 많은 경우에는 찾기가 정말 쉽지 않다.
개발 단계에서부터 신중하게 고려하며 작성하는 것이 중요할 것 같다.

0개의 댓글