2022. 9. 13. 13:32ㆍC++
C++은 모든 오브젝트가 최소 1byte의 크기를 가지고 있어야 하는데, 같은 타입의 오브젝트들의 주소 값이 각각 구별되어야 하기 때문이다. 이 제약은 클래스 멤버 변수로 선언된 객체와 같은 member suboejct라고 달라지지 않는데, 이 제약이 적용되지 않을 때가 있다. 바로 크기가 0인 클래스가 상속된 경우이다. 다음 코드를 보자.
struct Base
{
// Nothing
}
struct Derived : Base
{
int x;
}
어떤 자식 클래스의 객체를 생성하면 멤버 변수의 객체들 뿐만 아니라 부모 클래스 객체 또한 생성되는데, 이 부모 객체를 base class subobject라고 하며, 멤버 변수들을 member subobject라고 한다. 따라서 위 코드의 Derived 클래스 메모리 레이아웃은 다음과 같이 구성된다. (참고로 subobject가 아닌 객체들을 complete object라고 한다.)

모든 오브젝트가 최소 1byte의 크기를 가진다는 제약에 따르면 위 코드에서 Derived 클래스는 alignment padding을 고려하면 8byte를 가지는 것이 맞을 것이다. 하지만, sizeof(Derived)의 값은 4가 되는데, C++ 표준에 의해 크기가 0인 base class subobject는 0 byte를 차지하도록 보장되어 있기 때문이다.
An object has nonzero size if it
- is not a potentially-overlapping subobject, or
- is not of class type, or
- is of a class type with virtual member functions or virtual base classes, or
- has subobjects of nonzero size or unnamed bit-fields of nonzero length.
Otherwise, if the object is a base class subobject of a standard-layout class type with no non-static data members, it has zero size.
이러한 최적화를 Empty Base Optimization, 줄여서 EBO라고 한다.
EBO가 적용되지 않는 경우도 존재하는데, 자식 클래스의 base class subobject의 타입이 첫 번째 member subobject와 타입이 일치하거나 부모 타입인 경우가 그렇다.
struct Base
{
};
struct Derived1 : Base
{
int x;
};
struct Derived2 : Base
{
Derived1 d;
};
이 경우 Derived2 객체의 메모리 레이아웃은 다음과 같을 것이다.

하지만 이 글 처음에 같은 타입의 객체들은 주소 값이 구별되야 한다고 했다. 즉, Derived2와 Derived1의 base class subobject의 크기가 둘 다 0이면 주소가 같게 되므로 EBO가 적용이 될 수 없는 것이다. 따라서 이 경우는 Derived2의 base class subobject의 크기가 1이 되며, sizeof(Derived2)의 값은 alignment padding을 고려하면 4가 아닌 1byte (Derived2::Base) + 3byte (padding) + 4byte (Derived1::x) = 8이 된다. (clang, gcc는 8을 출력하는데, msvc에서는 4를 출력한다. msvc가 표준을 안따르는건가..?)
[참고]
- http://eel.is/c++draft/intro.object
'C++' 카테고리의 다른 글
std::intializer_list는 어떻게 생성 및 파괴될까? (1) | 2022.09.16 |
---|---|
std::string_view를 값으로 전달해야 하는 3가지 이유 (번역) (1) | 2022.09.13 |
문자열 리터럴을 템플릿 인자로 전달하는 방법 (0) | 2022.04.02 |
Literal Class Type as Non-type Template Parameter (0) | 2022.04.02 |
Template Template Parameter (0) | 2022.03.25 |