얕은 복사(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 &copy) //복사 생성자

: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
Posted by scii
: