복사 생성자와 복사 대입 연산자

김펭귄·2025년 5월 5일

C++

목록 보기
18/20

1. 복사 생성자와 복사 대입 연산자 차이

  • 복사 생성자:

    • 새로운 객체를 기존 객체로 초기화할 때 호출됨
    • 객체가 "처음 만들어질 때"만 사용됨
  Book b1("C++", 300);
  Book b2 = b1; 
  Book b3(b2);  
  • 복사 대입 연산자:
    • 이미 생성된 객체에 다른 객체를 대입할 때 호출됨
  Book b1("C++", 300);
  Book b2;	// 생성자 호출됨
  b2 = b1;	// 복사 대입 연산자 호출. 복사 생성자는 호출 안 됨
  b2.operator=(b1);  // b2 = b1이 호출하는 실제 코드. 같은 동작

2. 복사 대입 연산자

2-1. 기본 복사 대입 연산자

  • 사용자가 직접 정의하지 않으면 컴파일러가 기본 복사 대입 연산자 자동 생성

  • 모든 멤버 변수를 1:1로 복사 (주소값만 복사 → 얕은 복사)

  • 복사 생성자와 동일하게 포인터 멤버와 관련한 얕은 복사의 문제점 발생


2-2. 복사 대입 연산자 정의하는 방법

  • 기본 구조
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;
    }
};

2-3. 참고 사항

  1. this
  • this는 객체 자신을 가리키는 포인터
  • 클래스의 비정적 멤버 함수 내에서 사용 가능하며, 해당 멤버 함수를 호출한 객체의 주소를 담고 있음
  • a.operator=(b);가 호출되면, this는 객체 a의 주소
  • 따라서 .operator=의 반환형이 Book&이므로 *this를 반환

  1. 대입 연산자에서 참조를 반환하는 이유
  • 연속 대입(chaining assignment)을 가능하게 하기 위함
  a = b = c;
  • 먼저 b = c가 수행되고,
  • 그 결과 b 객체가 a = ...의 우변으로 전달되어 a = b가 수행
  • 참조를 반홤하으로써 연속대입이 가능

  1. 자기 대입 처리
Book b;
b = b; // 문제 발생 방지

if (this == &other)로 검사하지 않으면 기존 리소스가 삭제된 후 자기 데이터에 접근하므로 에러 발생

  1. 예외 안전성
  • 새 메모리 할당 성공 후 기존 메모리 해제하기
  • 메모리 할당 실패 시 원본 객체가 파괴되지 않도록

  1. 리소스 누수 방지
  • 반드시 기존 리소스를 먼저 해제한 후 복사

3. 복사 생성자 vs 복사 대입 연산자

구분복사 생성자복사 대입 연산자
호출 시점새 객체 생성 시기존 객체에 대입 시
구문Book b2 = b1;b2 = b1;
정의 방법Book(const Book& other)Book& operator=(const Book& other)
default 생성O (사용자 정의 없을 시)O (사용자 정의 없을 시)
주요 목적객체 초기화객체 상태 업데이트

4. Rule of Three

  • 복사 생성자, 복사 대입 연산자, 소멸자 중 하나라도 직접 정의하면 모두 직접 정의하는 것이 좋다는 규칙
profile
반갑습니다

0개의 댓글