C++ 복사 생성자의 얕은 복사 과정 ?

조회수 854회
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass()
    {
        pnumber = new int(5);
    }

    ~MyClass()
    {
        delete pnumber;
    }

    int number = 0;
    int *pnumber = nullptr;
};

int main()
{

    MyClass a;
    a.number = 300;
    cout << "a.n의 값 " << a.number << endl;
    cout << "a.pn의 값 " << *a.pnumber << endl;
    cout << "a.pn의 주소값 " << a.pnumber << endl;

    MyClass b(a);
    cout << "b.n의 값 " << b.number << endl;
    cout << "b.pn의 값 " << *b.pnumber << endl;
    cout << "b.pn의 주소값 " << b.pnumber << endl;

    a.number = 400;

    return 0;
}

이미지

아직 학부생이라 정확히 어떻게 질문을 해야할 지 몰라서 제목 및 질문이 좀 난해한 점 사과드립니다.

위 코드에서 인스턴스 b는 디폴트 복사 생성자를 통해 a를 복사하는데, 이 때 제가 배운 바로는

디폴트 복사 생성자는 얕은 복사기 때문에 그림과 같이 b.pnumber 변수는 a.pnumber가 가리키는 new int(5)를 가리키는 형태로 복사가 된다.

이 때 소멸자에 delete pnumber 가 포함되어 있으므로 이미 해제된 메모리(빨간 화살표)를 다시 해제하는 꼴이 되어 에러가 발생한다.

이렇게 알고있습니다.

여기서 궁금한 점은

a.pnumber는 생성자의 pnumber = new int(5) 코드를 통해 명백하게 할당을 받게 되는데, 복사 생성자로 생성된 b.number는 (복사 생성자로 그림과 같이 되기 이전에) 과연 할당을 받는가? 받는다면 어떠한 과정을 통해 언제 받게 되는가? 에 대한 것입니다.

에러가 발생했을 때

(1) b.pnumber가 new int(5) (빨간화살표)를 할당받음 -> 얕은 복사로 인한 메모리 (빨간화살표) 해제 -> 이미 해제된 영역을 소멸자 코드가 다시 해제를 요청하여 에러 발생

(2) b.pnumber는 생성과 동시에 a.pnumber를 얕은 복사함 -> 새로이 할당받은 적이 없음 -> 애초에 할당받지 못한 영역을 소멸자 코드가 해제 요청하여 에러 발생

이 둘 중 어떤 과정이 맞는 것인지 궁금합니다.

책이나 강의 등에서는 모두 (1)과 같이 얕은 복사 이전에 이미 어느 시점엔가 b.pnumber는 할당을 받았다는 전제가 깔리던데 이에 대한 설명은 따로 없어서 질문 드렸습니다.

감사합니다.

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

1 답변

  • 기본 복사 생성자는 아마 그냥 복사만 할 겁니다. 그게 포인터더라도요.

    컴파일러는 포인터가 가리키고 있는 게 하나여야 하는지, 둘이어야 하는지 모르니까 (이건 프로그래머가 결정할 문제니까) 그냥 주소만 복사를 해버리거든요...

    그래서 b.pnumber는 할당을 받는 게 아니라 a.pnumber를 복사합니다. 즉, 복사 생성자에서는 b.pnumber = a.pnumber 가 일어납니다. b.pnumber에 대한 new는 어디에서도 일어나지 않습니다.

    &(a.pnumber)0x20180419 였다면 &(b.pnumber)0x20180419 이고, 이는 A의 생성자에서 실행된 new int(5) 라는 수식이 반환한 주소인 0x20180419 와 같습니다. 메모리 위치 0x20180419 에 있는 정수는 하나인데 정작 복사되는 건 메모리 위치를 가리키는 숫자인 0x20180419 뿐인 거죠.

    C / C++에서 포인터의 얕은 복사란 그저 주소값을 그대로 복사하는 것을 의미합니다. 주소도 정수값이니까요.

    (2) 가 정답처럼 보이네요.

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

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

(ಠ_ಠ)
(ಠ‿ಠ)