Namespaces
Variants

Empty base optimization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

빈 기본 하위 객체의 크기를 0으로 허용합니다.

목차

설명

모든 객체 또는 멤버 하위 객체의 크기는 해당 유형이 빈 클래스 유형 (즉, 비정적 데이터 멤버가 없는 클래스 또는 구조체)인 경우에도 최소 1이어야 합니다, ( [[ no_unique_address ]] 를 사용하지 않는 한, 아래 참조) (C++20부터) 동일한 유형의 서로 다른 객체들의 주소가 항상 구별된다는 것을 보장하기 위함입니다.

그러나 기본 클래스 하위 객체는 이러한 제약을 받지 않으며, 객체 레이아웃에서 완전히 최적화되어 제거될 수 있습니다:

struct Base {}; // empty class
struct Derived1 : Base
{
    int i;
};
int main()
{
    // the size of any object of empty class type is at least 1
    static_assert(sizeof(Base) >= 1);
    // empty base optimization applies
    static_assert(sizeof(Derived1) == sizeof(int));
}

빈 기본 클래스 최적화는 빈 기본 클래스 중 하나가 첫 번째 비정적 데이터 멤버의 타입이거나 그 타입의 기본 클래스인 경우 금지됩니다. 왜냐하면 동일한 타입의 두 기본 하위 객체는 가장 파생된 타입의 객체 표현 내에서 서로 다른 주소를 가져야 하기 때문입니다.

이러한 상황의 전형적인 예는 빈 베이스 std::iterator 에서 파생된 std::reverse_iterator 의 나이브 구현으로, 이는 기본 반복자(역시 std::iterator 에서 파생됨)를 첫 번째 비정적 데이터 멤버로 보유합니다.

struct Base {}; // empty class
struct Derived1 : Base
{
    int i;
};
struct Derived2 : Base
{
    Base c; // Base, occupies 1 byte, followed by padding for i
    int i;
};
struct Derived3 : Base
{
    Derived1 c; // derived from Base, occupies sizeof(int) bytes
    int i;
};
int main()
{
    // empty base optimization does not apply,
    // base occupies 1 byte, Base member occupies 1 byte
    // followed by 2 bytes of padding to satisfy int alignment requirements
    static_assert(sizeof(Derived2) == 2*sizeof(int));
    // empty base optimization does not apply,
    // base takes up at least 1 byte plus the padding
    // to satisfy alignment requirement of the first member (whose
    // alignment is the same as int)
    static_assert(sizeof(Derived3) == 3*sizeof(int));
}

빈 베이스 최적화는 필수적입니다 StandardLayoutType s 에 대해, 표준 레이아웃 객체의 포인터가 reinterpret_cast 를 사용하여 변환될 때 해당 객체의 첫 번째 멤버를 가리키도록 하기 위한 요구사항을 유지하기 위해서입니다. 이것이 표준 레이아웃 타입의 요구사항에 "모든 비정적 데이터 멤버가 동일한 클래스에서 선언되어야 함(모두 파생 클래스에 있거나 모두 일부 베이스 클래스에 있음)"과 "첫 번째 비정적 데이터 멤버와 동일한 타입의 베이스 클래스를 가지지 않아야 함"이 포함되는 이유입니다.

(C++11부터)

빈 멤버 서브오브젝트는 [[ no_unique_address ]] 속성을 사용하는 경우, 빈 베이스 클래스와 마찬가지로 최적화되어 제거될 수 있습니다. 이러한 멤버의 주소를 취하면 동일한 객체의 다른 멤버 주소와 동일한 주소가 반환될 수 있습니다.

struct Empty {}; // empty class
struct X
{
    int i;
    [[no_unique_address]] Empty e;
};
int main()
{
    // the size of any object of empty class type is at least 1
    static_assert(sizeof(Empty) >= 1);
    // empty member optimized out:
    static_assert(sizeof(X) == sizeof(int));
}
(C++20부터)

참고 사항

빈 베이스 최적화는 할당자 인식 표준 라이브러리 클래스들( std::vector , std::function , std::shared_ptr 등)에서 할당자가 상태를 가지지 않는 경우 해당 할당자 멤버가 추가 저장 공간을 차지하지 않도록 하기 위해 흔히 사용됩니다. 이는 필요한 데이터 멤버 중 하나(예: begin , end , 또는 vector capacity 포인터)를 할당자와 함께 boost::compressed_pair 의 동등한 구조에 저장함으로써 달성됩니다.

MSVC에서 빈 기본 클래스 최적화는 표준 요구 사항과 완전히 호환되지 않습니다 ( Why is the empty base class optimization (EBO) is not working in MSVC? ).

참고문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 7.6.10 동등 연산자 [expr.eq]
  • 7.6.2.5 Sizeof [expr.sizeof]
  • 11 클래스 [class]
  • 11.4 클래스 멤버 [class.mem]
  • C++20 표준(ISO/IEC 14882:2020):
  • 7.6.10 동등 연산자 [expr.eq]
  • 7.6.2.4 Sizeof [expr.sizeof]
  • 11 클래스 [class]
  • 11.4 클래스 멤버 [class.mem]
  • C++17 표준(ISO/IEC 14882:2017):
  • 8.10 동등 연산자 [expr.eq]
  • 8.3.3 Sizeof [expr.sizeof]
  • 12 클래스 [class]
  • 12.2 클래스 멤버 [class.mem]
  • C++14 표준(ISO/IEC 14882:2014):
  • 5.10 동등 연산자 [expr.eq]
  • 5.3.3 Sizeof [expr.sizeof]
  • 9 클래스 [class]
  • 9.2 클래스 멤버 [class.mem]
  • C++11 표준 (ISO/IEC 14882:2011):
  • 5.10 동등 연산자 [expr.eq] (p: 2)
  • 5.3.3 Sizeof [expr.sizeof] (p: 2)
  • 9 클래스 [class] (p: 4,7)
  • 9.2 클래스 멤버 [class.mem] (p: 20)
  • C++98 표준 (ISO/IEC 14882:1998):
  • 5.10 동등 연산자 [expr.eq] (p: 2)
  • 5.3.3 Sizeof [expr.sizeof] (p: 2)
  • 9 클래스 [class] (p: 3)

외부 링크

More C++ Idioms/Empty Base Optimization — 위키책