복사 생성자:
Book b1("C++", 300);
Book b2 = b1;
Book b3(b2);
Book b1("C++", 300);
Book b2; // 생성자 호출됨
b2 = b1; // 복사 대입 연산자 호출. 복사 생성자는 호출 안 됨
b2.operator=(b1); // b2 = b1이 호출하는 실제 코드. 같은 동작
사용자가 직접 정의하지 않으면 컴파일러가 기본 복사 대입 연산자 자동 생성
모든 멤버 변수를 1:1로 복사 (주소값만 복사 → 얕은 복사)
복사 생성자와 동일하게 포인터 멤버와 관련한 얕은 복사의 문제점 발생
ClassName& operator=(const ClassName& other) {
if (this == &other) return *this; // 1. 자기 대입 방지
// 2. 기존 리소스 해제
// 3. 새 리소스 할당 및 복사
// 4. 기본 타입 멤버 복사
return *this; // 5. 자기 참조 반환
}
class Book {
char* title;
public:
Book& operator=(const Book& other) {
if (this == &other) return *this; // 1
delete[] title; // 2
title = new char[strlen(other.title) + 1]; // 3
strcpy(title, other.title);
return *this;
}
};
thisthis는 객체 자신을 가리키는 포인터a.operator=(b);가 호출되면, this는 객체 a의 주소.operator=의 반환형이 Book&이므로 *this를 반환a = b = c;
- 먼저
b = c가 수행되고,- 그 결과 b 객체가 a = ...의 우변으로 전달되어
a = b가 수행- 참조를 반홤하으로써 연속대입이 가능
Book b;
b = b; // 문제 발생 방지
if (this == &other)로 검사하지 않으면 기존 리소스가 삭제된 후 자기 데이터에 접근하므로 에러 발생
| 구분 | 복사 생성자 | 복사 대입 연산자 |
|---|---|---|
| 호출 시점 | 새 객체 생성 시 | 기존 객체에 대입 시 |
| 구문 | Book b2 = b1; | b2 = b1; |
| 정의 방법 | Book(const Book& other) | Book& operator=(const Book& other) |
| default 생성 | O (사용자 정의 없을 시) | O (사용자 정의 없을 시) |
| 주요 목적 | 객체 초기화 | 객체 상태 업데이트 |