C++에서 객체의 직접(direct) 및 간접(copy) 초기화를 구분합니다:
직접 초기화:
MyClass obj(arg1, arg2); int x(5);
클래스의 경우 적절한 생성자를 직접 호출합니다.
간접 초기화:
MyClass obj = MyClass(arg1, arg2); int x = 5;
이는 임시 객체를 생성한 다음 이를 복사(또는 이동)합니다(복사 생성자/이동 생성자를 사용).
차이점:
예제:
struct NonCopyable { NonCopyable(int) {} NonCopyable(const NonCopyable&) = delete; }; NonCopyable a(5); // OK: 직접 NonCopyable b = NonCopyable(5); // 최적화 시 OK, C++17 이전에는 오류 NonCopyable c = 5; // 오류: 복사 생성자가 없음
"C++11을 사용하고 최적화된 컴파일러가 켜져 있다면, copy-initialization이 direct-initialization보다 더 많은 생성자 호출을 일으킬 수 있습니까?"
답변: 이론적으로는 가능합니다. copy elision이 없으면 copy-initialization은 임시 객체를 생성하고, 이후 복사 생성자 또는 이동 생성자를 호출합니다. Direct-initialization은 항상 기본 생성자만 호출합니다. 그러나 현대 컴파일러는 최적화가 활성화되어 있을 경우(예: C++17 이상) guaranteed copy elision을 통해 이러한 차이를 제거합니다.
이야기
금융 프로젝트에서 임시 객체와 함께 copy-initialization을 사용했지만 필요한 타입에 복사 생성자가 없었습니다. 애플리케이션은 오래된 컴파일러(C++17 이전)에서는 컴파일되지 않았지만 direct-init은 작동했습니다.
이야기
데이터 직렬화 유틸리티에서 프로그래머들은 direct-init과 copy-init이 동등하다고 생각했습니다. 결과적으로 대형 구조체의 불필요한 복사와 성능 저하가 발생했습니다.
이야기
사용자 정의 객체의 전역 배열 초기화 시 간접 초기화를 사용했습니다. 오류는 copy elision이 발생하지 않는 단일 플랫폼에서만 나타났고, ABI의 특성으로 인해 불필요한 생성자의 암시적 호출이 발생했습니다.