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의 인자를 전달
함수 내에서 객체를 값에 의해 리턴
'C++' 카테고리의 다른 글
[C++] 예외처리 // 열혈강의 (0) | 2016.12.14 |
---|---|
[C++] 템플릿 // 열혈강의 (0) | 2016.12.12 |
[C++] 레퍼런스 정리 (0) | 2016.12.07 |
[C++] 연산자 오버로딩 // 열혈강의 (0) | 2016.12.07 |
[C++] virtual 소멸자, virtual table // 열혈강의 (0) | 2016.12.05 |