[C++] Chapter 05 정리
복사 생성자(Copy Constructor)
다음과 같은 생성자를 '복사 생성자(Copy Constructor)'라 한다.
Simple(const Simple ©) : num1(copy.num1), num2(copy.num2) {
cout << "Called Simple(Simple ©)" << endl;
}
디폴트 복사 생성자
복사 생성자의 삽입 없이도 멤버 대 멤버의 복사가 진행 가능하며 이것은 복사 생성자를 정의하지 않으면, 멤버 대 멤버의 복사를 진행하는 디폴트 복사 생성자가 자동으로 삽입되기 때문이다.
이 때문에 많은 경우에서는 복사 생성자를 따로 정의하지 않아도 된다.
explicit
explicit 키워드를 이용해 복사 생성자의 묵시적 호출을 허용하지 않을 수도 있다.
explicit Simple(const Simple ©) : num1(copy.num1), num2(copy.num2) {
}
이렇게 될 경우 묵시적 변환이 발생하지 않아 아래와 같이 대입 연산자를 이용한 객체의 생성 및 초기화가 불가능해진다.
- Simple simple1 = simple2;
'깊은 복사'와 '얕은 복사'
디폴트 복사 생성자는 멤버 대 멤버의 복사를 진행하고, 이러한 방식의 복사를 가리켜 '얕은 복사(Shallow Coply)'라 한다. 이는 멤버변수가 힙의 메모리 공간을 참조하는 경우에 문제가 발생한다.
디폴트 복사 생성자의 문제점
하나의 문자열을 두 개의 객체가 동시에 참조하는 것과 같은 경우, 객체의 소멸 과정에서 하나의 객체가 먼저 소멸된 뒤, 남아있는 객체가 소멸될 시 이미 지워진 문자열을 대상으로 delete 연산을 하기 때문에 문제가 발생한다.
'깊은 복사'를 위한 복사 생성자의 정의
다음과 같이 복사 생정자를 정의하면, 객체 별로 각각의 문자열을 참조하기 때문에 객체의 소멸 과정에서 문제가 발생하지 않는다.
Person(const Person& copy) : age(copy.age) {
name = new char[strlen(copy.name) + 1];
strcpy(name, copy.name);
}
위의 생성자가 하는 일은 다음 두 가지이다.
- 멤버변수 age의 멤버 대 멤버 복사
- 메모리 공간 할당 후 문자열 복사, 그리고 할당된 메모리의 주소 값을 멤버 name에 저장
이러한 형태의 복사를 가리켜 '깊은 복사(Deep Copy)'라 한다.
복사 생성자의 호출시점
복사 생성자가 호출되는 시점은 크게 아래 세 가지로 구분할 수 있다.
- 기존에 생성된 객체를 이용해서 새로운 객체를 초기화하는 경우
- Call-by-value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우
- 객체를 반환하되, 참조형으로 반환하지 않는 경우
이것들은 모두 객체를 새로 생성하며, 생성과 동시에 동일한 자료형의 객체로 초기화해야 한다는 공통점이 있다.
이를 설명하기 위해 설명할 메모리 공간이 할당과 동시에 초기화 되는 상황들은 아래와 같다.
- int n1 = n2;
- Func(n); // 호출되는 순간 매개변수가 할당과 동시에 초기화
- return n; // 반환하는 순간 메모리 공간이 할당되면서 동시에 초기화
이러한 상황은 객체를 대상으로 해도 달라지지 않으며, 위 복사 생성자 호출 시점에 각각 대응됨을 알 수 있다.
임시객체(Temporary Object)
객체의 반환 시, 임시객체라는 것이 생성되고 임시객체의 참조 값이 반환된다. 그리고 임시객체는 참조자에 의해 참조되지 않는 다면 다음 행으로 넘어가면서 즉시 소멸된다.