프로그래밍/C++

얕은 복사와 깊은 복사

우대비 2022. 10. 23. 09:40
반응형

어떠한 '클래스를 상속받은 객체'를 복사 생성자, 복사 대입 연산자를 통해 복사할때

'주의 해야할 점'이 한가지 있는데 바로 '컴파일러는 알잘딱 해주지 않는다'는 거임

 

이게 무슨 소리냐

1) 깊은 복사 [ 명시적 복사 생성자, 명시적 복사 대입 연산자 ]

class Knight : public Player
{
public:
	Knight()
	{
	}
	Knight(const Knight& knight)
	{
		cout << "Knight(const Knight&)" << endl;
		_hp = knight._hp;
	}
	
	Knight& operator=(const Knight& knight)
	{
		cout << "operator=(const Knight&)" << endl;
		_hp = knight._hp;
		return *this;
	}

	~Knight()
	{

	}

public:
	int _hp = 100;
	Pet _pet;
};

 

위와 같은 'Player를 상속받고 Pet 객체를 가지고 있는 클래스'가 있을때

int main()
{
	Knight knight; // 기본 생성자
	knight._hp = 200;

	cout << "-------------------복사생성자-------------------" << endl;
	Knight knight2 = knight; // 복사 생성자



	cout << "-------------------복사 대입 연산자-------------------" << endl;
	Knight knight4; // 기본 생성자
	knight4 = knight; // 복사 대입 연산자
    return 0;
}

 

위의 코드처럼 '복사 생성자, 복사 대입 연산자를 호출'하면 '어디까지 복사를 해줄까'를 보면

놀랍게도 Player, Pet을 '기본 생성자로 생성'하는걸 볼 수 있음

즉 Player, Pet 안에 있는 데이터들을 안옮겨 준다는 얘기임

 

Player()
Pet()
-------------------복사생성자-------------------
Player()
Pet()
Knight(const Knight&)
-------------------복사 대입 연산자-------------------
Player()
Pet()
operator=(const Knight&)
~Pet()
~Pet()
~Pet()

 

위와 같은 결과가 출력됨

즉 '명시적으로' 복사 생성자와 복사 대입 연산자를 '호출 할때'에는

부모 클래스랑 멤버 클래스를 '컴파일러가' 알잘딱 해주지 않기 때문에 '프로그래머가' 알잘딱해줘야한다~

 

2) 앝은 복사 [ 암시적 복사 생성자, 암시적 복사 대입 연산자 ]

class Knight : public Player
{
public:


public:
	int _hp = 100;
	Pet _pet;
};

위 처럼 복사 생성자, 복사 대입 연산자에 대한 정의가 없을 때

int main()
{
	Knight knight; // 기본 생성자
	knight._hp = 200;

	cout << "-------------------복사생성자-------------------" << endl;
	Knight knight2 = knight; // 복사 생성자



	cout << "-------------------복사 대입 연산자-------------------" << endl;
	Knight knight4; // 기본 생성자
	knight4 = knight; // 복사 대입 연산자
    return 0;
}

위의 코드를 다시 실행 시켜보면

 

Player()
Pet()
-------------------복사생성자-------------------
Player(const Player&)
Pet(const Pet&)
-------------------복사 대입 연산자-------------------
Player()
Pet()
operator=(const Player&)
operator=(const Pet&)
~Pet()
~Pet()
~Pet()

 

깊은 복사와 다르게 결과가 출력되는걸 볼 수 있음

'부모 클래스와 맴버 클래스'를 기본 생성자로 생성 하는 것이 아닌 '복사 생성자, 복사 대입 연산자'로 생성하는데

와! 컴파일러 알잘딱! 이라고 착각 할 수가 있음

 

하지만 이러한 얕은 복사의 경우 '치명적인 문제'가 하나 있음

바로 포인터의 경우 '포인터의 주소값까지 복사'해버린다는 거..

 

객체를 복사 하고 '원본과 복사본'의 메모리를 delete로 반환할때

똑같은 주소값을 가지고 있는, 즉 같은 객체에 두번 delete하게 되는거

그럼 크래쉬가 나게됨..

 


 

반응형
LIST

'프로그래밍 > C++' 카테고리의 다른 글

함수포인터  (0) 2022.10.31
캐스팅  (0) 2022.10.24
클래스의 복사  (0) 2022.10.22
virtual 소멸자  (0) 2022.10.22
동적할당  (0) 2022.10.20