Abseil Tip 172 지정 초기화자(Designated Initializers)

주간 팁 #172: 지정 초기화자(Designated Initializers)

원래 TotW #172로 2019년 12월 11일 게시됨
작성자: Aaron Jacobs
2020-04-06 업데이트됨

빠른 링크: abseil.io/tips/172

지정 초기화자는 구조체의 내용을 간결하면서도 읽기 쉽고 유지보수 가능한 방식으로 지정하기 위한 C++20 표준의 문법입니다. 다음과 같은 반복적인 코드를 작성하는 대신:

struct Point {
  double x;
  double y;
  double z;
};

Point point;
point.x = 3.0;
point.y = 4.0;
point.z = 5.0;

지정 초기화자를 사용하여 다음과 같이 작성할 수 있습니다:

Point point = {
    .x = 3.0,
    .y = 4.0,
    .z = 5.0,
};

이 방식은 반복 작업을 줄이는 데 도움이 될 뿐만 아니라, 더 다양한 상황에서도 사용할 수 있습니다. 예를 들어, 구조체를 const로 설정하여 번거로운 우회 작업 없이도 변경 불가능하게 만들 수 있습니다:

// 코드가 복잡한 경우 이 구조체가 절대 변경되지 않음을 독자에게 명확히 알립니다.
const Point character_position = { .x = 3.0 };

또는 추가 식별자를 범위 내에 도입하지 않고도 함수 호출에서 직접 사용할 수 있습니다:

std::vector<Point> points;
[...]
points.push_back(Point{.x = 3.0, .y = 3.0});
points.push_back(Point{.x = 4.0, .y = 4.0});

의미론

지정 초기화자는 집합 초기화의 한 형태로, 집합에서만 사용할 수 있습니다. 이는 “사용자 정의 생성자나 가상 함수가 없는 구조체 또는 클래스”를 의미하며, 일반적으로 Google 스타일에서는 class 대신 struct를 사용할 때 해당됩니다.

C++20 지정 초기화자의 의미론은 생성자에서의 멤버 초기화 목록과 같은 다른 C++ 언어 기능을 기반으로 예상할 수 있는 동작을 합니다. 명시적으로 언급된 필드는 제공된 표현식으로 초기화되며, 기본 동작을 원할 경우 필드를 생략할 수 있습니다:

Point point = {
    .x = 1.0,
    // y는 0.0으로 설정됨
    .z = 2.0,
};

위에서 “기본값”은 무엇을 의미할까요? 특별한 경우(예: union)를 제외하고, 다음과 같습니다:

  • 구조체 정의에 기본 멤버 초기화자가 포함된 경우(예: std::string foo = "default value";), 해당 값이 사용됩니다.
  • 그렇지 않으면 필드는 = {}로 초기화된 것처럼 설정됩니다. 이는 기본 데이터 유형의 경우 0 값이 설정되고, 더 복잡한 클래스의 경우 기본 생성된 인스턴스를 얻는 것을 의미합니다.

이 동작은 일반적으로 가장 예상 가능한 결과를 제공합니다. 자세한 내용은 표준을 참조하세요.


역사와 언어 트리비아

지정 초기화자는 C99 이후 C 언어의 표준적인 일부였으며, 이전부터 컴파일러에서 비표준 확장으로 제공되었습니다. 하지만 최근까지는 C++의 일부가 아니었습니다. 이는 C가 C++의 부분 집합이 아니었던 주목할 만한 예입니다. 이로 인해 Google 스타일 가이드는 사용하지 말 것을 권장하기도 했습니다.

20년이 지나 상황이 바뀌었습니다. 이제 지정 초기화자는 C++20 표준의 일부가 되었습니다.

C++20의 지정 초기화자는 C 버전에 비해 몇 가지 제한이 있습니다:

  • C++20에서는 필드가 구조체 정의에 나열된 순서대로 지정자에 나열되어야 합니다(따라서 Point{.y = 1.0, .x = 2.0}는 유효하지 않음). C에서는 이를 요구하지 않습니다.
  • C에서는 지정된 초기화자와 지정되지 않은 초기화자를 혼합할 수 있지만(예: Point{1.0, .z = 2.0}), C++20에서는 이를 허용하지 않습니다.
  • C에서는 “배열 지정자(array designators)”로 알려진 희소 배열 초기화를 지원하지만, 이는 C++20의 일부가 아닙니다.