c++ - Discrepancy in C++ between over-aligned struct and enum within container
问题描述
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
解决方案
This is C++ core working group issue 2354, which was recently resolved by removing the permission to apply alignas
to an enum
type. (At the time of writing, the latest public version of the issues list doesn't contain the resolution, but you can find the resolution in P1359R0, which was adopted into the C++ working draft in February 2019 and accepted as a Defect Report (which means the fix is intended to apply retroactively).
The problem is that we had two conflicting requirements:
an enum-base (including the implicit enum-base of
int
in a scoped enumeration) specifies the underlying type of the enumeration, and the enumeration is required to have the same object representation (includingsizeof
and representation of all values) as its underlying type, andan alignment-specifier specifies the alignment of the type, which in turn must also constrain
sizeof(E)
(which is by definition the distance between two objects of typeE
in an array) to a multiple of said alignment.
You can't have both, so we resolved the conflict by removing the ability to specify an alignment on an enumeration type.
The best advice is to not apply an alignment specifier to an enumeration type; implementations will stop accepting that at some point. (Applying the alignment to a use of the type in the declaration of a variable or non-static data member is OK, though.)
推荐阅读
- c++ - 指针数组。获取指针元素的值
- jfugue - 为节拍器无限循环播放 JFugue 模式
- html - 添加 data-container="body" 后,工具提示在表内不起作用
- php - 从PHP中的数组中提取特定类型的元素
- python - 仅对 python 中的特定索引与相应的对进行排序
- java - SpringBoot scanBasePackages 在不同的 jar 中找不到存储库
- jquery - JQuery 和 Bootstrap:Bad Nav Dropdown Bug
- python - python:arg_parser 参数添加别名
- swift - 在alamofire中发送数组数组
- xml - 使用 powershell 格式化 csv 中的 xml 字段