简体   繁体   中英

Nested C Array Struct Alignment in Clang

I have a small memory problem in C++17 using Clang compiling for x64. Since I work with low level memory copies to specialized hardware, I do depend on the memory being aligned as expected. I have recently moved from Visual Studio to Clang and have encountered the following issue:

See the below code:

struct ContainerRoot{};
template<size_t t_size, class t_type>
struct Container : public ContainerRoot
{
    t_type contents[t_size];
};

static_assert(sizeof(Container<1, double>) == 8);           //This works as expected
static_assert(sizeof(Container<4, double>) == 32);          //This works as expected
static_assert(sizeof(Container<16, double>) == 128);        //This works as expected
static_assert(sizeof(Container<4, Container<4, double>>) == 128); //This fails. 

In the above example sizeof(Container< Container>) is actually 136 (an extra 8 bytes). My question is why is an extra 8 bytes getting added in, and can I avoid it? I would love to use the Clang compiler, but if there isn't a workaround for this, it may not be worth rewriting all of the code surrounding sending this data to the specialized hardware.

Thus far, I have checked using std::is_polymorphic< Container <4, Container<4, double>>>() just to confirm there wasn't some virtual lookup table being added to the class.

Quoting en.cppreference.com :

The size of any object or member subobject [...] is required to be at least 1 even if the type is an empty class type (that is, a class or struct that has no non-static data members), in order to be able to guarantee that the addresses of distinct objects of the same type are always distinct.

This constraint doesn't apply to empty bases (Empty Base Optimization).

However, en.cppreference.com also notes:

Empty base optimization is prohibited if one of the empty base classes is also the type or the base of the type of the first non-static data member, since the two base subobjects of the same type are required to have different addresses within the object representation of the most derived type.

Which is unfortunately the case when dealing with Container<4, Container<4, double>> as both the first member, which has type Container<4, double> , as well as Container<4, Container<4, double>> both inherit from ContainerRoot .

As such I would hypothesize that MSVC is actually wrong in this case and prematurely applies an optimization which it must not do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM