복사 생성자
복사 생성자는 객체가 복사될 때 자동으로 호출되는 함수를 의미합니다.
복사 생성자는 어떤 클래스 T 가 있다면
T(const T& a);
라고 정의됩니다. 즉, 다른 T의 객체 a를 상수 레퍼런스로 받습니다.
얕은 복사
객체를 초기화할 때 똑같은 클래스로 생성한 객체를 대입하면 멤버 변수들이 그대로 복사됩니다. 이때 정적으로 할당된 멤버 변수는 변수가 생성되고 값이 복사됩니다.
반면에 동적으로 할당된 멤버 변수는 메모리를 할당하지 않고 대입한 객체의 멤버 변수를 포인터로 참조합니다. 이를 얕은 복사라고 합니다.
class Person
{
private:
char* name;
int age;
public:
Person(const char myname[], int myage)
{
int len = strlen(myname) + 1;
name = new char[len];
strcpy_s(name, len, myname);
age = myage;
}
void ShowPersonInfo() const
{
cout << "이름: " << name << endl;
cout << "나이: " << age << endl;
}
~Person()
{
delete[] name;
cout << "called destructor!" << endl;
}
};
int main()
{
Person man1("Lee dong woo", 29);
Person man2 = man1; // 얕은 복사
man1.ShowPersonInfo();
man2.ShowPersonInfo();
return 0;
}
이름: Lee dong woo
나이: 29
이름: Lee dong woo
나이: 29
called destructor! //소멸자가 한번만 호출
얕은 복사로 인해 똑같은 메모리 영역을 참조하고 있는데, 첫 번째 객체를 소멸하고 두 번째 객체에서 같은 메모리를 해제하려고 시도하기 때문에 오류가 발생합니다.
깊은 복사
이를 해결하기 위해 동적으로 메모리가 할당된 멤버 변수의 값은 깊은 복사가 이뤄져야 합니다. 메모리를 새로 할당해 내용을 복사하는 방식으로, 컴파일러가 생성하는 디폴트 복사 생성자의 경우 얕은 복사밖에 못하므로 깊은 복사는 사용자가 직접 복사 생성자를 만들어야 합니다.
Person(const Person& copy) : age(copy.age)
{
name = new char[strlen(copy.name) + 1];
strcpy(name, copy.name);
}
복사 생성자의 호출 시점
case 1 : 기존에 생성된 객체를 이용해서 새로운 객체를 초기화하는 경우
Person man1("Lee dong woo", 29);
Person man2 = man1; // 복사 생성자 호출
case 2 : Call-by-value 방식의 함수 호출 과정에서 객체를 인자로 전달하는 경우
case 3 : 객체를 반환하되, 참조형으로 반환하지 않는 경우
SoSimple SimpleFunctionObj(SoSimple ob) // case 2
{
...
return ob; // case 3
}
int main()
{
SoSimple obj;
SimpleFunctionObj(obj);
....
}
'내일배움캠프 > TIL' 카테고리의 다른 글
[사전 캠프 Day9] 팀 프로젝트 진행 (0) | 2024.12.12 |
---|---|
[사전 캠프 Day6] 언리얼 소스 코드 다운받기 (1) | 2024.12.09 |
[사전 캠프 Day4] STL (6) | 2024.12.05 |
[사전 캠프 Day3] Unreal 에셋 (3) | 2024.12.05 |
[사전 캠프 Day2] Unreal이란 무엇인가요? (3) | 2024.12.03 |