
https://github.com/POCU/COMP3200CodeSamples
<aside> 💡 목차
</aside>
<aside> 💡 묵시적 복사생성자 - 컴파일러는 기본적으로 복사생성자를 생성시킨다
해당 글에서, 컴파일러는 자동으로 복사생성자를 하나 만들어준다고 했었지?
자동으로 생성된 복사생성자는 얕은복사 문제가 발생할 수 있었다고 함
아래는 얕은 복사가 어떻게 발생하는지 시각적으로 알아볼것임
</aside>
<aside> 💡 컴파일러가 묵시적으로 생성해준 복사생성자는 다음과 같은 모양이다

classRecord는 new를 사용하지 않았기 때문에,
스택에 생성되겠죠?
우측에 classRecord 부분에는 멤버변수 4바이트 두개가 할당된것을 볼 수 있습니다.
힙 영역에 개체를 생성시키기 위해 생성한 포인터 개체 변수도 4바이트만큼 스택에 할당되었군요

ClassRecord(socre, 5) 를 실행해봅시다.
입력값으로 5가 들어갔기 때문에 mScore = new int[5] 가 되겠죠?
이는 곧 int 5개 들어가는 메모리를 힙 영역에 할당을 했다는 의미이구
2048은 이제 힙 영역에 mScores가 할당된 첫번째를 가르키는 주소입니다.

자 이제 힙 영역에 복사 생성자를 호출할 차레에요.
new classRecord(classRecord)
그리고 이거는 new로 선언되었기 때문에, 힙 영역에 들어가야 돼요\
결국 이 클래스, 이 오브젝트 자체가 힙에 들어가겠죠?
그런 이유로 스택에는 그 오브젝트를 가르키는 주소값 4바이트만 들어간것이구요

힙 영역에 오브젝트를 생성하면, 스택에 8바이트 생성되었듯이, 힙 영역에 8바이트가 할당됩니다
//(멤버 변수의 int mCount, int* mScores 두개가 들어감)
그러고 동적 할당받은 영역의 시작 주소가 1024였기 때문에 classRecordCopy()를 가르키는 변수는 스택에 1024가 저장이 되어있는 겁니다
그런데 힙 영역에 저장된 int* mScores 에는 2048을 가르키고 있습니다.
기존 classRecord()의 mScores를 그냥 그대로 대입해와서 주소를 그대로 복사해온겁니다
결국
classRecordCopy()의 int *mScore는
classRecord()의 int *mScore와
동일한 주소를 가르키고 있는 꼴이 된것이죠

이렇게 원본 객체와 복사된 객체가 같은 주소를 가르키고 있는 상태에서 delete를 하게되면 이제 이런 일이 일어나요
delete classRecordCopy;
방금 생성한 classRecordCopy() 를 힙 영역에서 제거하면, 기존에 힙 영역을차지하고있던 8바이트가 제거되면서
classRecordCopy()의 소멸자가 호출이 되잖아요?
그럼 소멸자는 mScores를 지워요, 그럼 아까 가르키고있던 2048주소의 데이터들을 지워버리게 됩니다.
근데 이걸 어째? classRecord()는 아직 스택에 살아있는데?
근데 가리키고 있는 2048 주소에는 방금 소멸자가 생성되며 데이터가 날라가버렸네???
그래서 이런 식으로 데이터를 공유하는 건 위험한 일이에요,
사실 저희가 여태까지 생성자에서 메모리 잡고 memcpy() 하는 이유도 이런 거 피하기 위함이었어요 그렇죠?
그래서 결론은 이런게 얕은 복사의 문제점중 하나입니다.
</aside>
<aside> 💡 얕은복사문제를 피하기 위해 프로그래머가 깊은복사를 구현한 방법이다
포인터 변수가 가르키는 실제 데이터까지도 복사하는 경우다
글을 읽기 전, memcpy() 의 사용법을 숙지하고 아래 글을 읽자
[memcpy() 어케씀?](https://cybecho.notion.site/memcpy-26259506abf945b1abe525ef5cfcafaa)

깊은복사의 기본 코드
이것도 복사 생성자 맞죠?
그럼 mCount에 대입하는 것까진 똑같아요
그런데 아까 scores를 그냥 쓰면 안 됐어요, 그렇죠?
그럼 그 mCount 만큼 새로 나만의 사본을 먼저 만들고
그 사본을 새롭게 생성되는 복사 개체에 복사해오는 거죠
이러면 저만의 카피가 생겨서 제가 가진 힙 영역의 메모리를 지워도
원래 복사되었던 원본 객체의 데이터는 안전하겠죠?
memcpy (this->mScores, other.mScores, this->mCount * sizeof(int));
소멸자 만드는 거랑 되게 좀 비슷하긴 하죠
동적으로 메모리를 생성하고 있다면 얕은 복사가 이제 일어날 가능성이 이 얕은 목사가 일어나면 그걸로 인해 문제가 생길 가능성이 매우 높죠,
왜? 포인터를 그냥 복사해오면
복사된 객체쪽에서 지워버리거나 수정하면 원본 데이터도 영향받는 문제가 있어서
이것을 직접 포인터에 있는 내용까지 포인터 속에 있는 내용까지 복사해오는 방법이 깊은 복사입니다.
</aside>
<aside> 💡 깊은복사의 실제 코드를 함께 보자

깊은 복사 구현했다는 가정 하에 이제 하는 거예요 여기까지는 처음 메모리 똑같이 보이죠? 그럼 그다음 단계부터 보면 될 것 같아요

이제 복사 생성자를 힙 영역에 생성해봅시다.
새로 메모리 8바이트를 힙 영역에 잡고 새롭게 잡은 힙 영역의 메모리의 시작 주소는 스택에 올라가는것까진 같습니다.
새롭게 잡은 힙 영역의 시작주소는 2048이군요.
그렇다면 classRecordCopy() 라는 변수에 달라진 점은 뭘까요?
복사된 int *mScores가 가르키는 주소가 원본 객체의 *mScores가 가르키던 4096이 아니네요?
왜 이렇냐면, 복사되면서 mScores에 대한 메모리 새로 할당을 했기 떄문이에요.
메모리를 먼저 새롭게 할당하고, 기존 원본 데이터가 가르키던 주소의 데이터들을 복사 해가지고
이렇게 자신이 새롭게 할당받은 힙 영역에 복사해와서, 같은 데이터값을 가지지만?
전혀 별개의 메모리 주소에 있게 된것이죠

그럼 이제 delete classRecordCopy() 로 동적 할당된 객체를 지워볼까요?
소멸자가 자동으로 호출되면서 가리키고 있던 데이터들을 다 지우겠죠?
그러면 아까와 다르게 사본만 지워지고 원본은 안전하게 살아있어요.
그래서 이런 경우에 명시적으로 복사 생성자를 만들어야 돼요,
즉 내부에서 메모리 할당하고 있다면 명시적으로 복사 생성자를 만들어야 될 가능성이 높다~!
그렇게 보시면 됩니다
</aside>