Constructors and member initializer lists
생성자 는 특별한 선언자 구문으로 선언된 비정적 멤버 함수 로, 자신의 클래스 타입 객체를 초기화하는 데 사용됩니다.
|
생성자는 코루틴 이 될 수 없습니다. |
(C++20부터) |
|
생성자는 명시적 객체 매개변수 를 가질 수 없습니다. |
(C++23부터) |
목차 |
구문
생성자는 다음과 같은 형태의 멤버 function declarators 를 사용하여 선언됩니다:
class-name
(
parameter-list
(선택 사항)
)
except
(선택 사항)
attr
(선택 사항)
|
|||||||||
| class-name | - | 식별자 표현식, 뒤에 속성 목록이 올 수 있으며, (C++11부터) 괄호 쌍으로 둘러싸일 수 있음 | ||||||
| parameter-list | - | 매개변수 목록 | ||||||
| except | - |
|
||||||
| attr | - | (C++11부터) 속성 목록 attributes |
생성자 선언의
선언 지정자
에서 허용되는 유일한 지정자는
friend
,
inline
,
constexpr
(C++11부터)
,
consteval
(C++20부터)
, 그리고
explicit
입니다 (특히, 반환 타입은 허용되지 않습니다).
cv- 및 ref-한정자
도 허용되지 않는다는 점에 유의하십시오: 생성 중인 객체의 const 및 volatile 의미론은 가장 파생된 생성자의 완료 이후에만 적용됩니다.
class-name 의 식별자 표현식은 다음 형식 중 하나를 가져야 합니다:
-
- 클래스의 경우, 식별자 표현식은 바로 바깥쪽 클래스의 injected-class-name 입니다.
- 클래스 템플릿의 경우, 식별자 표현식은 current instantiation 를 지칭하는 클래스 이름입니다 (C++20까지) 바로 바깥쪽 클래스 템플릿의 injected-class-name (C++20부터) 입니다.
- 그렇지 않으면, 식별자 표현식은 터미널 비한정 식별자가 해당 조회 컨텍스트의 주입된 클래스 이름인 한정된 식별자입니다.
멤버 초기화 리스트
클래스
T
의 임의의 생성자의
함수 정의
본문에서, 복합문의 여는 중괄호 앞에는
멤버 초기화 리스트
가 포함될 수 있으며, 그 구문은 콜론 문자
:
와 그 뒤에 쉼표로 구분된 하나 이상의
member-initializer
목록으로 구성됩니다. 각 멤버 초기화자는 다음 구문을 가집니다:
| 멤버 초기화 | (1) | ||||||||
| 클래스 초기화 | (2) | ||||||||
클래스-팩
초기화
...
|
(3) | (C++11 이후) | |||||||
|
(C++11부터) |
-
T의 직접 기반 클래스나 virtual base class . 이 경우 해당 기반 클래스 하위 객체는 initializer 로 직접 초기화됩니다.
| member | - | 데이터 멤버를 명명하는 식별자 |
| class | - | 클래스 이름 |
| class-pack | - | 0개 이상의 클래스로 확장되는 팩 |
| initializer | - |
=
로 시작하지 않는
initializer
|
struct S { int n; S(int); // 생성자 선언 S() : n(7) {} // 생성자 정의: // ": n(7)"는 초기화 리스트 // ": n(7) {}"는 함수 본문 }; S::S(int x) : n{x} {} // 생성자 정의: ": n{x}"는 초기화 리스트 int main() { S s; // S::S() 호출 S s2(10); // S::S(int) 호출 }
설명
생성자는 이름이 없으며 직접 호출할 수 없습니다. 생성자는 초기화 가 발생할 때 호출되며, 초기화 규칙에 따라 선택됩니다. explicit 지정자가 없는 생성자는 변환 생성자 입니다. constexpr 지정자를 가진 생성자는 해당 타입을 리터럴 타입 으로 만듭니다. 인수 없이 호출할 수 있는 생성자는 기본 생성자 입니다. 동일한 타입의 다른 객체를 인수로 받는 생성자는 복사 생성자 와 이동 생성자 입니다.
생성자의 함수 본문을 구성하는 복합 문장이 실행을 시작하기 전에, 모든 직접 기반 클래스, 가상 기반 클래스, 그리고 비정적 데이터 멤버의 초기화가 완료됩니다. 멤버 초기화 목록은 이러한 하위 객체들의 비기본 초기화를 지정할 수 있는 곳입니다. 기본 초기화될 수 없는 기반 클래스들과 기본 초기화 또는 기본 멤버 초기화 (있는 경우)로 초기화될 수 없는 비정적 데이터 멤버들 (C++11부터) , 예를 들어 참조형과 const 한정 타입의 멤버들에 대해서는 반드시 멤버 초기화를 지정해야 합니다. (클래스 템플릿 인스턴스화의 비정적 데이터 멤버에 대한 기본 멤버 초기화는 멤버 타입이나 초기화자가 종속적일 경우 유효하지 않을 수 있습니다.) (C++11부터) 멤버 초기화가 없는 익명 공용체 나 variant 멤버 에 대해서는 초기화가 수행되지 않습니다 또는 기본 멤버 초기화 (C++11부터) .
초기화자에서 class 가 가상 기본 클래스를 명시하는 경우, 생성 중인 객체의 가장 파생된 클래스가 아닌 모든 클래스의 생성 중에는 무시됩니다.
initializer 에 나타나는 이름들은 생성자의 범위에서 평가됩니다:
class X { int a, b, i, j; public: const int& r; X(int i) : r(a) // X::r을 X::a를 참조하도록 초기화합니다 , b{i} // X::b를 매개변수 i의 값으로 초기화합니다 , i(i) // X::i를 매개변수 i의 값으로 초기화합니다 , j(this->i) // X::j를 X::i의 값으로 초기화합니다 {} };
멤버 초기화자에서 발생하는 예외는 function try block 에 의해 처리될 수 있습니다.
|
비정적 데이터 멤버가 기본 멤버 초기화자 를 가지고 동시에 멤버 초기화 리스트에도 나타나는 경우, 멤버 초기화자가 사용되며 기본 멤버 초기화자는 무시됩니다: struct S { int n = 42; // default member initializer S() : n(7) {} // will set n to 7, not 42 }; |
(C++11부터) |
참조 멤버는 멤버 초기화 리스트에서 임시 객체에 바인딩될 수 없습니다:
struct A { A() : v(42) {} // 오류 const int& v; };
참고: 동일한 내용이 default member initializer 에도 적용됩니다.
생성 및 소멸 중의 연산
멤버 함수들(
가상 멤버 함수
포함)는 생성 중이거나 파괴 중인 객체에 대해 호출될 수 있습니다. 마찬가지로, 생성 중이거나 파괴 중인 객체는
typeid
또는
dynamic_cast
의 피연산자가 될 수 있습니다.
그러나 다음 평가 중 하나가 수행되는 동안 이러한 연산이 실행되면, 그 동작은 정의되지 않습니다:
|
(C++26부터) |
- 모든 멤버-초기화 가 완료되기 전에 멤버 초기화 목록을 평가하는 것
위임 생성자만약 클래스 이름 자체가 멤버 초기화 목록에서 class-or-identifier 로 나타나는 경우, 해당 목록은 해당 멤버 초기화 항목 하나로만 구성되어야 합니다; 이러한 생성자를 위임 생성자 라고 하며, 초기화 목록의 유일한 멤버에 의해 선택된 생성자는 대상 생성자 입니다. 이 경우 대상 생성자는 오버로드 해결에 의해 선택되어 먼저 실행된 후, 제어가 위임 생성자로 돌아와 해당 본문이 실행됩니다. 위임 생성자는 재귀적일 수 없습니다. class Foo { public: Foo(char x, int y) {} Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char, int) }; 생성자 상속참조: using 선언 . |
(C++11부터) |
초기화 순서
멤버 초기화자 목록의 순서는 중요하지 않으며, 실제 초기화 순서는 다음과 같습니다:
(참고: 초기화 순서가 서로 다른 생성자의 멤버 초기화 목록에 나타나는 순서에 의해 제어된다면, destructor 는 파괴 순서가 생성 순서의 역순이 되도록 보장할 수 없을 것입니다.)
참고 사항
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_delegating_constructors
|
200604L
|
(C++11) | 위임 생성자 |
예제
#include <fstream> #include <string> #include <mutex> struct Base { int n; }; struct Class : public Base { unsigned char x; unsigned char y; std::mutex m; std::lock_guard<std::mutex> lg; std::fstream f; std::string s; Class(int x) : Base{123}, // 베이스 클래스 초기화 x(x), // x (멤버)는 x (매개변수)로 초기화됨 y{0}, // y는 0으로 초기화됨 f{"test.cc", std::ios::app}, // 이 초기화는 m과 lg가 초기화된 후에 수행됨 s(__func__), // __func__은 초기화 목록이 생성자의 일부이므로 사용 가능 lg(m), // lg는 이미 초기화된 m을 사용함 m{} // m은 여기서 마지막에 나타나지만 lg보다 먼저 초기화됨 {} // 빈 복합문 Class(double a) : y(a + 1), x(y), // x는 y보다 먼저 초기화되므로, 여기서의 값은 불확정적임 lg(m) {} // 베이스 클래스 초기화자는 목록에 나타나지 않으며, // 기본 초기화됨 (Base()를 사용한 값 초기화와 다름) Class() try // 함수 try 블록은 함수 본문 이전에 시작하며, 초기화 목록을 포함함 : Class(0.0) // 위임 생성자 { // ... } catch (...) { // 초기화 중 예외 발생 } }; int main() { Class c; Class c1(1); Class c2(0.1); }
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 194 | C++98 |
생성자의 선언자 구문이 최대 하나의 함수 지정자만 허용함
(예: 생성자를 inline explicit 로 선언할 수 없음) |
여러 함수 지정자
허용 |
| CWG 257 | C++98 |
추상 클래스가 가상 기본 클래스에 대한 멤버 초기화자를
제공해야 하는지 명시되지 않음 |
필요하지 않도록 명시하고
해당 멤버 초기화자는 실행 중 무시됨 |
| CWG 263 | C++98 |
생성자의 선언자 구문이
생성자가 friend가 되는 것을 금지함 |
생성자가 friend가 되는 것
허용 |
| CWG 1345 | C++98 |
기본 멤버 초기화자가 없는 익명 유니온 멤버가
기본 초기화됨 |
초기화되지 않음 |
| CWG 1435 | C++98 |
생성자의 선언자 구문에서 "클래스 이름"의 의미가
불명확함 |
구문을 특수화된 함수 선언자
구문으로 변경 |
| CWG 1696 | C++98 |
참조 멤버를 임시 객체로 초기화할 수 있었음
(해당 임시 객체의 수명은 생성자 종료 시 끝남) |
해당 초기화는
올바르지 않은 형식 |
참조문헌
- C++23 표준(ISO/IEC 14882:2024):
-
- 11.4.5 생성자 [class.ctor]
-
- 11.9.3 기반 클래스 및 멤버 초기화 [class.base.init]
- C++20 표준(ISO/IEC 14882:2020):
-
- 11.4.4 생성자 [class.ctor]
-
- 11.10.2 기반 클래스 및 멤버 초기화 [class.base.init]
- C++17 표준(ISO/IEC 14882:2017):
-
- 15.1 생성자 [class.ctor]
-
- 15.6.2 기반 클래스 및 멤버 초기화 [class.base.init]
- C++14 표준(ISO/IEC 14882:2014):
-
- 12.1 생성자 [class.ctor]
-
- 12.6.2 기반 클래스 및 멤버 초기화 [class.base.init]
- C++11 표준(ISO/IEC 14882:2011):
-
- 12.1 생성자 [class.ctor]
-
- 12.6.2 기반 클래스 및 멤버 초기화 [class.base.init]
- C++98 표준(ISO/IEC 14882:1998):
-
- 12.1 생성자 [class.ctor]
-
- 12.6.2 기본 클래스 및 멤버 초기화 [class.base.init]