C++를 공부하는 부분에 있어서

상속과 더불어 상당히 골치 아픈 부분 중 하나.

이번 포스팅에서 완벽하게 처리하고 가겠다.


1. 복사 생성자의 형태 --> 복사생성자도 생성자중에 하나


class AAA{

private:

int n;

public:

AAA(){}

AAA(int i) : n(i){};


AAA(const AAA& _a){

n = _a.n;

}

}


int main(){

AAA aaa(10);

AAA bbb(aaa);  ---> 멤버 변수가 복사된다.

}


---> 복사생성자도 생성자와 같이 디폴트 복사생성자가 존재한다. (얕은 복사)



2. 얕은 복사의 문제점, 깊은 복사


--> 클래스를 디자인할 때, 당장은 깊은 복사를 하지않더라도 확장성을 위해 (먼 미래를 위해)

복사생성자를 정의해두자


class AAA{

private:

char* name;

public:

AAA(char *_name) {

name = new char(strlen(_name)+1];

strcpy(name, _name);

}


~AAA(){ delete[] name }

};


int main(){

AAA aaa("kim");

AAA bbb(AAA);    --->> 디폴트 복사생성자가 호출된다. --> 오류가 난다 왜??

}


---> AAA 클래스 내의 멤버변수 name은 포인터로 힙 영역을 가리키고 있다.

따라서 bbb는 aaa가 가르키는 힙 영역을 그대로 가리키게 된다. (멤버 대 멤버 복사를 하기 때문) --> 주소값을 복사하게 된다.

--> bbb객체가 없어지면서 delete에 의해 메모리가 해제가 된다.

또한 여전히 그 공간을 가르키고 있는 aaa 객체에서도 같은 공간을 해제 하려한다. 

--> 하나의 메모리 공간을 두번 소멸하려 했기 때문 --> 문제 발생


AAA (const AAA& _a){

name = new char[strlen(_a.name)+1];

strcpy(name, _a.name);  

}


--> 디폴트 복사생성자는 얕은 복사를 제공하기 때문에, 깊은 복사를 사용자가 정의를 해주어야 한다.



3. 복사생성자의 호출시기


1. 

int main(){

AAA obj1(10);

AAA obj2(obj1);

}


기존의 객체가 새로운 객체를 초기화 하는 경우


2. 

void fct(AAA a){ ... };


int main(){

AAA obj(10);

fct(obj);             ----> 1. 메모리 공간 할당

2. 값 전달 --> 초기화 --> 값을 전달할 때 복사생성자가 호출된다.

}                                             --> 레퍼런스로 전달받으면 상관없는 일


함수에 매개변수로 전달이 될 때 (값에 의한 전달)


3. 


AAA fct(){

AAA a(10);

return a;

}


int main(){

fct();                 ---> 복사본이 리턴된다.    1. 함수 내의 a객체와 똑같은 형태로 메모리 공간 할당

fct().show();                                                2. 쓰레기값으로 초기화가 되어있다.

}                                                                          3. 복사본의 복사생성자를 호출하면서 a의 인자를 전달



함수 내에서 객체를 값에 의해 리턴



+ Recent posts