copy_constructor — 복사 생성자
copy_constructor — 복사 생성자
**복사 생성자(copy constructor)**는 같은 클래스 타입의 인자로 호출될 수 있고, 인자를 변경하지 않고 그 내용을 복사하는 생성자예요.
값으로 객체를 전달하거나 반환할 때, 또는 T a = b;처럼 같은 타입으로 복사 초기화할 때 호출돼요. 복사 생성자를 이해하면 객체가 어떻게 복사되는지 정확히 통제할 수 있어요.
출처: cppreference
본문
복사 생성자는 같은 클래스 타입의 인자로 호출될 수 있고, 인자를 변경하지 않고 그 내용을 복사하는 생성자예요.
문법 (Syntax)
class-name ( parameter-list ) ;
class-name ( parameter-list ) function-body
class-name ( single-parameter-list ) = default;
class-name ( parameter-list ) = delete;
class-name :: class-name ( parameter-list ) function-body
class-name :: class-name ( single-parameter-list ) = default;
class-name— 복사 생성자를 선언하는 클래스parameter-list— 다음 조건을 모두 만족하는 비어 있지 않은 매개변수 목록. 클래스 타입을T라 할 때 첫 매개변수는T&,const T&,volatile T&,const volatile T&중 하나고, 다른 매개변수는 없거나 모두 기본 인자를 가져야 해요.function-body— 복사 생성자의 함수 본문
설명 (Explanation)
복사 생성자는 같은 타입의 다른 객체로부터 (직접 초기화 또는 복사 초기화로) 초기화될 때 호출되는데, 여기에는 다음이 포함돼요 (과부하 해석이 더 나은 매치를 선택하거나 호출이 복사 생략되면 제외).
- 초기화:
T a = b;또는T a(b);(여기서b는T타입) - 함수 인자 전달:
f(a);(a는T타입,f는void f(T t)) - 함수 반환:
return a;(T f()함수 안,a는T타입, 이동 생성자가 없는 경우)
암시적으로 선언된 복사 생성자
클래스 타입에 사용자 정의 복사 생성자가 없으면, 컴파일러는 항상 복사 생성자를 그 클래스의 비-explicit inline public 멤버로 선언해요. 다음 조건이 모두 참이면 이 암시적으로 선언된 복사 생성자는 T::T(const T&) 형태예요.
T의 각 직접·가상 기반B가const B&또는const volatile B&타입 매개변수를 가진 복사 생성자를 가짐T의 클래스 타입/클래스 타입 배열의 각 비정적 데이터 멤버M이const M&또는const volatile M&타입 매개변수를 가진 복사 생성자를 가짐
그렇지 않으면 암시적으로 선언된 복사 생성자는 T::T(T&)예요. 이 규칙 때문에 암시적으로 선언된 복사 생성자는 volatile lvalue 인자에 바인딩될 수 없어요.
클래스는 여러 복사 생성자를 가질 수 있어요 (예: T::T(const T&)와 T::T(T&) 둘 다). C++11부터, 사용자 정의 복사 생성자가 있더라도 default 키워드로 암시적 복사 생성자 선언을 강제할 수 있어요.
암시적으로 정의된 복사 생성자
암시적으로 선언된 복사 생성자가 삭제되지 않았다면, ODR-사용되거나 상수 평가에 필요할 때 컴파일러가 정의해요. 유니언 타입에 대해서는 객체 표현을 복사하고(std::memmove처럼), 비유니온 클래스 타입에 대해서는 객체의 직접 기반 부분 객체와 멤버 부분 객체를 초기화 순서대로 직접 초기화를 이용해 전체 멤버별 복사를 수행해요. 참조 타입의 비정적 데이터 멤버 각각에 대해, 복사 생성자는 참조를 소스 참조가 바인딩된 같은 객체나 함수에 바인딩해요.
C++11부터, constexpr 생성자의 요구 사항을 만족하면 생성된 복사 생성자는 constexpr이 돼요. T에 사용자 정의 소멸자나 사용자 정의 복사 대입 연산자가 있으면 암시적으로 정의된 복사 생성자의 생성은 deprecated예요.
삭제된 복사 생성자
클래스 T에 대해 암시적으로 선언되거나 명시적으로 default 처리된 복사 생성자는 다음 조건 중 하나라도 만족하면 삭제된 것으로 정의돼요.
T가 rvalue 참조 타입의 비정적 데이터 멤버를 가짐 (C++11부터)T가 삭제됐거나 복사 생성자에서 접근 불가한 소멸자를 가진 클래스 타입의 부분 객체, 또는 복사 생성자 오버로드 해석이 사용 가능한 후보를 만들지 못하는 부분 객체를 가짐
C++11부터, T가 이동 생성자나 이동 대입 연산자를 선언하면 암시적으로 선언된 복사 생성자는 삭제된 것으로 정의돼요.
Trivial 복사 생성자
클래스 T의 복사 생성자는 다음이 모두 참이면 trivial이에요.
- 사용자 제공이 아님 (암시적으로 정의되거나 default 처리됨)
T가 가상 멤버 함수가 없음T가 가상 기반 클래스가 없음T의 각 직접 기반에 대해 선택된 복사 생성자가 trivialT의 클래스 타입(또는 클래스 타입 배열) 멤버 각각에 대해 선택된 복사 생성자가 trivial
비유니온 클래스의 trivial 복사 생성자는 인자의 모든 스칼라 부분 객체(재귀적으로)를 효과적으로 복사하고 다른 동작을 수행하지 않아요. 다만 패딩 바이트는 복사할 필요가 없고, 복사된 부분 객체의 객체 표현조차 값이 같다면 동일할 필요는 없어요.
TriviallyCopyable 객체는 객체 표현을 수동으로 복사해 복사할 수 있어요 (예: std::memmove). C 언어와 호환되는 모든 데이터 타입(POD 타입)은 trivially copyable이에요.
노트 (Notes)
많은 상황에서 복사 생성자는 관찰 가능한 부수 효과가 있더라도 최적화로 제거될 수 있어요 (복사 생략 참조).
결함 보고 (Defect reports)
- C++98에서 암시적으로 선언된 복사 생성자가 undefined인 조건이 다차원 배열 타입을 고려하지 않았지만, 이후 고려하도록 바뀌었어요.
- C++11에서 volatile 멤버가 복사를 비trivial하게 만들던 것이 triviality에 영향을 주지 않도록 바뀌었어요.
- C++11에서
X(X&) = default가 비trivial이던 것이 trivial로 만들어졌어요.