[C++] 복사 생성자 깊은복사 얕은복사
복사 생성자란 같은 클래스 타입의 다른 객체에 대한 참조를 받아, 그 참조를 통해 해당 객체를 초기화하는 방법입니다.
이러한 복사는 깊은 복사와 얕은 복사 2가지로 나누어집니다.
얕은 복사는 참조받는 객체의 메모리를 할당 하는 방법이고, 깊은 복사는 참조받는 객체의 메모리의 내용이 복사됩니다
복사 생성자도 디폴트 생성자 처럼 컴파일러가 알아서 만들어주기 때문에 특정 특별한 경우를 제외하고서는 굳이 정의하지않아도 됩니다. 복사 생성자를 정의해야 하는 경우는 클래스 내부에서 메모리를 동적 할당 및 해제하고 이를 멤버 포인터 변수로 관리하는 경우는 복사 생성자를 정의해야합니다
class Person
{
private:
char* name;
int* age;
public:
Person()
{
name = NULL;
age = 0;
}
Person(const char* _name, int _age)
{
name = new char[strlen(_name) + 1];
strcpy_s(name,strlen(_name)+1, _name);
age = new int(_age);
}
void GetPersonData()
{
cout << "이름 : " << name << '\n';
cout << "나이 : " << *age << '\n';
}
~Person()
{
delete[] name;
delete age;
}
};
int main()
{
Person SuDong("SuDong", 24);
Person DongSu(SuDong);
SuDong.GetPersonData();
DongSu.GetPersonData();
}
// 이름 : SuDong
// 나이 : 24
// 이름 : SuDong
// 나이 : 24
// ERROR
얕은 복사를 하였습니다 얕은 복사는 참조받은 객체의 메모리가 복사되는데 이때 참조타입 멤버가있다면 참조값이 복사됩니다
그리고 객체가 소멸될때 소멸자를 호출하게되는데 객체는 같은 메모리를 참조받고있어 DougSu 소멸자의 delete 이후 SuDong 소멸자의 delete 과정에서 에러가 발생하게됩니다
우리는 복사생성자의 얕은복사에 대한 이러한 문제들을 해결하기위해 깊은 복사에 대해 알아야합니다 깊은 복사생성자는 복사 생성자를 오버라이딩해줌으로써 멤버 변수들을 복사해줌으로써 문제를 해결하는 방식입니다.
위의 코드를 깊은 복사를 통해 오류를 해결해보겠습니다
#include"iostream"
#include<string.h>
using namespace std;
class Person
{
private:
char* name;
int* age;
public:
Person()
{
name = NULL;
age = 0;
}
Person(const char* _name, int _age)
{
name = new char[strlen(_name) + 1];
strcpy_s(name,strlen(_name)+1, _name);
age = new int(_age);
}
Person(Person& _person)
{
name = new char[strlen(_person.name) + 1];
strcpy_s(name, strlen(_person.name) + 1, _person.name);
age = new int(*_person.age);
}
void GetPersonData()
{
cout << "이름 : " << name << '\n';
cout << "나이 : " << *age << '\n';
}
~Person()
{
delete[] name;
delete age;
}
};
int main()
{
Person SuDong("SuDong", 24);
Person DongSu(SuDong);
SuDong.GetPersonData();
DongSu.GetPersonData();
}
디폴트 복사생성자가 아닌 복사 생성자를 오버라이딩하여 문제를 해결했습니다
메모리를참조하는 멤버의 복사가 있는 경우 메모리 해제와 같은경우 문제가 발생하기때문에 복사 생성자를 오버라이딩하여 복사 생성자를 따로만들어야 합니다 그렇지않은 경우 디폴트 복사 생성자가 존재하기때문에 얕은복사를 사용해도 됩니다