结构根据空基 class 顺序更改大小
Struct changes size based on empty base class order
我正在编写一个数学向量和矩阵库用于练习,我使用 crtp 基础 class 以便不必多次定义多个函数。我还继承了一个静态数组class。但是,根据继承的 classes 的顺序,我在 msvc 中为我的结构获得了不同的大小。这是一个错误,还是我应该预料到的?您可以在以下位置找到现场演示:https://godbolt.org/z/3EPVI5
请注意,在 gcc 中同样可以正常编译。
参考代码:
template<typename D>
struct crtp
{
};
template<typename T, int s>
struct arr_impl
{
T e[s];
};
template<typename T, int s>
struct vc : public arr_impl<T, s>, public crtp<vc<T, s>>
{
};
template<typename T, int s>
struct vc2 : public crtp<vc2<T, s>>, public arr_impl<T, s>
{
};
int main()
{
static_assert(sizeof(vc<vc<float,3>,2>) == 24);
static_assert(sizeof(vc2<vc2<float,3>,2>) == 24);
return 0;
}
我进一步缩小了范围,请参阅:https://godbolt.org/z/tGCn_J
因为看起来只需要嵌套和一个空的 class:
struct empty_struct{};
template<typename T>
struct st
{
T a;
};
template<typename T>
struct vc : public empty_struct, public st<T> {};
template<typename T>
struct vc2 : public st<T>, public empty_struct{};
int main()
{
static_assert(sizeof(vc<vc<float>>) == 4);
static_assert(sizeof(vc2<vc2<float>>) == 4);
return 0;
}
我相信 MSVC 在这方面符合 C++17 标准。
来自 [intro.object](强调我的):
Unless it is a bit-field, a most derived object shall have a nonzero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type shall occupy contiguous bytes of storage.
这就是 C++17 标准在这个问题上的全部内容。空基优化是完全可选的。标准只是说它是合法的,并不是说必须执行,或者在什么情况下应该执行。
C++20 标准的当前草案更具规范性。
来自 [intro.object](再次强调我的)
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 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. Otherwise, the circumstances under which the object has zero size are implementation-defined. Unless it is a bit-field, an object with nonzero size shall occupy one or more bytes of storage, including every byte that is occupied in full or in part by any of its subobjects. An object of trivially copyable or standard-layout type ([basic.types]) shall occupy contiguous bytes of storage.
因此,在 C++20 下,您的基 class 将保证具有零大小,因为它是 standard-layout class 的空基 class。
我正在编写一个数学向量和矩阵库用于练习,我使用 crtp 基础 class 以便不必多次定义多个函数。我还继承了一个静态数组class。但是,根据继承的 classes 的顺序,我在 msvc 中为我的结构获得了不同的大小。这是一个错误,还是我应该预料到的?您可以在以下位置找到现场演示:https://godbolt.org/z/3EPVI5 请注意,在 gcc 中同样可以正常编译。 参考代码:
template<typename D>
struct crtp
{
};
template<typename T, int s>
struct arr_impl
{
T e[s];
};
template<typename T, int s>
struct vc : public arr_impl<T, s>, public crtp<vc<T, s>>
{
};
template<typename T, int s>
struct vc2 : public crtp<vc2<T, s>>, public arr_impl<T, s>
{
};
int main()
{
static_assert(sizeof(vc<vc<float,3>,2>) == 24);
static_assert(sizeof(vc2<vc2<float,3>,2>) == 24);
return 0;
}
我进一步缩小了范围,请参阅:https://godbolt.org/z/tGCn_J 因为看起来只需要嵌套和一个空的 class:
struct empty_struct{};
template<typename T>
struct st
{
T a;
};
template<typename T>
struct vc : public empty_struct, public st<T> {};
template<typename T>
struct vc2 : public st<T>, public empty_struct{};
int main()
{
static_assert(sizeof(vc<vc<float>>) == 4);
static_assert(sizeof(vc2<vc2<float>>) == 4);
return 0;
}
我相信 MSVC 在这方面符合 C++17 标准。
来自 [intro.object](强调我的):
Unless it is a bit-field, a most derived object shall have a nonzero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type shall occupy contiguous bytes of storage.
这就是 C++17 标准在这个问题上的全部内容。空基优化是完全可选的。标准只是说它是合法的,并不是说必须执行,或者在什么情况下应该执行。
C++20 标准的当前草案更具规范性。
来自 [intro.object](再次强调我的)
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 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. Otherwise, the circumstances under which the object has zero size are implementation-defined. Unless it is a bit-field, an object with nonzero size shall occupy one or more bytes of storage, including every byte that is occupied in full or in part by any of its subobjects. An object of trivially copyable or standard-layout type ([basic.types]) shall occupy contiguous bytes of storage.
因此,在 C++20 下,您的基 class 将保证具有零大小,因为它是 standard-layout class 的空基 class。