깊은 복사 & 얕은 복사
Programming/C++ 2012. 5. 24. 04:41 |얕은 복사(Shallow Copy)
디폴트 복사 생성자는 멤버대 멤버의 복사를 진행한다. 그리고 이러한 방식의 복사를 가리켜 '얕은 복사(shallow copy)' 라 하는데, 이는 멤버변수가 힙의 메모리 공간을 참조하는 경우에 문제가 된다.
디폴트 복사 생성자는 멤버 대 멤버의 단순 복사를 진행하기 때문에 복사의 결과로 하나의 문자열을 두 개의 객체가 동시에 참조하는 꼴을 만들어버린다. 그리고 이로 인해서 객체의 소멸과정에서 문제가 발생한다.
만약에, man2가 소멸이 된다고 치면, man1도 소멸이 될 것이다. 하지만 name이 참조하는 문자열은(힙 영역) 이미 소멸된 상태이다. 그런데 man1에서 또 다시 delete []name;을 통해 힙 영역에 접근에 delete를 하려고 하니까 문제가 발생하는 것이다.
& 이미 지워진 문자열을 대상으로 delete연산을 하기 때문에 문제가 된다. 따라서 복사 생성자를 정의할 때에는 이러한 문제가 발생하지 않도록 신경을 써야 한다.
깊은 복사(Deep Copy)
: 얕은 복사의 문제점은 힙 영역이였다. 이 문제를 해결하려면 힙 영역을 따로 하나 더 만들면 되는것이다. 그러면 객체 별로 각각의 문자열을 촘조하기 때문에 위에서 언급한 객체 소멸과정에서의 문제는 발생하지 않는다.
이러한 형태의 복사를 가리켜 "깊은 복사(deep copy)" 라 한다. 멤버뿐만 아니라 포인터로 참조하는 대상까지 깊게 복사한다는 뜻이다.
위에 소스코드에서
Person(const Person& copy) : (copy.age)
{
name = new char[strlen(copy.name)+1];
strcpy(name, copy.name);
}
이 생성자만 추가해주면 문제가 발생하지 않는다.
위의 복사 생성자가 하는 일은 다음 두가지이다.
1. 멤버변수 age의 멤버 대 멤버 복사.
2. 메모리 공간 할당후 문자열 복사, 그리고 할당된 메모리의 주소 값을 멤버 name에 저장.
- 복사 생성자의 또 다른 예 -
#include <iostream>
#include <cstring>
using namespace std;
namespace COMP_POS
{
enum {CLERK, SENIOR, ASSIST, MANAGER};
void Select(int sel)
{
switch(sel)
{
case CLERK:
cout<<"사원"<<endl; break;
case SENIOR:
cout<<"주임"<<endl; break;
case ASSIST:
cout<<"대리"<<endl; break;
case MANAGER:
cout<<"과장"<<endl; break;
}
}
}
class NameCard
{
char * name;
char * company;
char * phone;
int position;
public:
NameCard(char* name, char* company, char* phone, int pos) //생성자
:position(pos)
{
this->name = new char[strlen(name)+1];
this->company = new char[strlen(company)+1];
this->phone = new char[strlen(phone)+1];
strcpy(this->name, name);
strcpy(this->company, company);
strcpy(this->phone, phone);
}
explicit NameCard(NameCard ©) //복사 생성자
:position(copy.position)
{
name = new char[strlen(copy.name)+1];
company = new char[strlen(copy.company)+1];
phone = new char[strlen(copy.phone)+1];
strcpy(name, copy.name);
strcpy(company, copy.company);
strcpy(phone, copy.phone);
}
void ShowNameCardInfo(void) const
{
cout<<"이름: "<<name<<endl;
cout<<"회사: "<<company<<endl;
cout<<"전화번호: "<<phone<<endl;
cout<<"직급: "; COMP_POS::Select(position);
cout<<endl;
}
~NameCard() //소멸자
{
delete []name;
delete []company;
delete []phone;
cout<<"Called Destructor"<<endl;
}
};
int main(void)
{
NameCard manClerk("lee", "ABC", "010-2323-1233", COMP_POS::CLERK);
NameCard copy1(manClerk);
NameCard manSENIOR("HaHo", "BOD", "010-7656-1235", COMP_POS::SENIOR);
NameCard copy2(manSENIOR);
copy1.ShowNameCardInfo();
copy2.ShowNameCardInfo();
return 0;
}
'Programming > C++' 카테고리의 다른 글
const 객체와 const 객체의 특성 그리고 const 함수 오버로딩 (0) | 2012.05.26 |
---|---|
복사 생성자의 호출시점 (0) | 2012.05.25 |
explicit (0) | 2012.05.23 |
복사 생성자(Copy Constructor) (0) | 2012.05.22 |
this 포인터 (0) | 2012.05.21 |