문제의 역사:
클래식 C++에서는 클래스 멤버가 오직 생성자 초기화 목록에서만 초기화되었습니다. C++11부터는 코드의 가독성과 안전성을 높이기 위해 클래스 내부 선언에서 기본값을 직접 지정하는 기능(member initializers)이 추가되었습니다.
문제:
클래스 멤버에게 값을 지정하는 여러 가지 방법이 있습니다: 직접 선언(in-class), 생성자 초기화 목록을 통해, 그리고 생성자 본문 내에서. 각 방법은 성능과 의미에 영향을 미치며, 잘못 이해하면 불필요한 복사나 기본 소멸자, 상수 및 참조에 대한 오류를 초래할 수 있습니다.
해결책:
class MyClass { int x = 42; };
class MyClass { const int y; MyClass(int val) : y(val) {} // 그렇지 않으면 컴파일 오류 };
class MyClass { std::string s; MyClass() { s = "hello"; } // 먼저 기본값이 설정되고 후에 할당 };
주요 특징:
클래스에서 멤버의 초기화 순서는 어떻게 결정됩니까? 선언 순서대로, 아니면 초기화 리스트 순서대로?
초기화 순서는 항상 클래스 내에서 멤버가 선언된 순서대로이며, 초기화 리스트의 순서와는 무관합니다. 이 순서를 위반하는 것은 의존적인 멤버에게 위험합니다.
class A { int x = 1; int y = 2; A() : y(10), x(20) {} }; // y는 초기화 리스트의 순서와 관계없이 x보다 나중에 초기화됩니다.
초기화 리스트에서 초기화되지 않은 상수 멤버를 생성자 본문에서 초기화할 수 있습니까?
아니요. 상수는 초기화 리스트에서만 초기화할 수 있습니다. 생성자 본문에서의 할당은 컴파일 오류입니다.
클래스에서 in-class initializer를 사용하여 멤버에 대해 기본값을 지정하고 생성자 초기화 리스트에서 재정의하면 어떻게 됩니까?
생성자 초기화 리스트의 값이 사용됩니다. 기본값은 초기화 리스트가 아무것도 지정하지 않을 때만 사용됩니다.
class C { int x = 10; C() : x(20) {} // x는 20이 됩니다. };
클래스가 파일 작업을 수행합니다. 파일은 std::ofstream으로 선언되고 생성자 본문에서 초기화됩니다. 위험: 기본 생성자에서 유효하지 않은 std::ofstream이 생성될 수 있어 파일 작업 중 오류가 발생합니다.
장점:
단점:
파일이 초기화 리스트에서 초기화되어 유효하지 않은 상태의 파일 사용을 방지하며, 기본 데이터를 가진 멤버는 in-class initializer를 사용합니다.
장점:
단점: