In C++, on at least GCC and Clang, an over-aligned type embedded within a container (std::vector) seems to be treated differently depending on whether the type is an over-aligned struct or an over-aligned enum. For the struct version, the element is aligned for each, while for the enum one, only the overall buffer is with the specified alignment. Is this behavior specified by the standard? And if so, which part does mention it? Or implementation-defined and should not be relied upon?
Consider the following:
#include<cstdint>
#include<iostream>
#include<vector>
struct alignas(16) byte_struct {std::uint8_t value;};
enum alignas(16) byte_enum : std::uint8_t {};
int main() {
{//with struct
std::vector<byte_struct> bytes;
bytes.push_back(byte_struct{1});
bytes.push_back(byte_struct{2});
bytes.push_back(byte_struct{3});
for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
std::cout<<&*it<<std::endl;
}
}
{//with enum
std::vector<byte_enum> bytes;
bytes.push_back(byte_enum{1});
bytes.push_back(byte_enum{2});
bytes.push_back(byte_enum{3});
for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
std::cout<<&*it<<std::endl;
}
}
}
The version with the over-aligned struct prints the following
0x10a9ec0 0x10a9ed0 0x10a9ee0
The version with the over-aligned enum prints the following
0x10a9e70 0x10a9e71 0x10a9e72
Within the vector storage, each byte_struct is aligned to 16 bytes boundary, as opposed to the byte_enum for which the alignment applies only to the buffer as a whole but not for each individual element.
This behavior is identical on GCC 9.1 and Clang 8.0, while MSVC 19.20 encounters an internal compiler error.
The link for compiler explorer is: https://godbolt.org/z/GUg2ft
byte_enum
should be aligned: "...it can be applied to the declaration or definition of a class/struct/union or enumeration." Just OOC, does it help matters if you actually define (at least) four enumerated identifiers? Casting to anenum
type beyond the range of the bit field necessary to represent the underlying enumeration is undefined behavior in C++17, so the compilers are allowed to break out the nasal demons without those definitions. – Pestilentbyte_enum{1}
? If so, aggregate initialization of enum with specified underlying type by a constant expression should be fine. Otherwise, it throws a narrowing warning/error. – Norty