绕过c++严格的别名规则
Getting around c++ strict-aliasing rules
我想在一个容器中存储一定数量的项。我不想使用数组,因为我想避免不必要的对象构造函数调用。由于隐含的malloc
调用,我不想使用std::vector
(我想尽量减少对堆的访问,以实现最大的缓存一致性(。
所以我开始定义我自己的自定义容器,类似这样:
template<typename T, size_t capacity> class my_array {
private:
char buffer[sizeof(T)*capacity];
...
public:
T& operator[](size_t i) { return *(T*)&buffer[i*sizeof(A)]; }
...
};
但当我尝试实际使用这个容器时,我会收到编译器关于违反严格别名规则的警告。我读过关于严格混叠的文章,我理解为什么编译器优化会导致上面的代码中断。
我该如何解决这个问题?
奇怪的是,我的编译器对我的自定义object_pool
类没有任何抱怨,除其他外,我将其用作关联STL数据结构的自定义分配器。该类看起来与上面的非常相似(使用char[]
并执行类似的强制转换(。我搞不清两者之间的区别。
使用std::array
!
如果您不打算使用std:array
,则
char buffer[sizeof(T)*capacity];
应该是
T buffer[capacity]
这就是为什么模板首先支持typename
。
如果您不想按照std::array
的要求初始化对象,请使用std::aligned_storage
。您可能会遇到对齐问题,因为您的结构可能被分配到一个奇怪的地址。
使用char
数组别名将其用作存储应该是可以的,我不确定您的编译器在做什么。这真的是一个最小的测试用例吗?
我通过与我在原始帖子中提到的object_pool
类进行精确比较,找到了一个神秘的解决方案。
我更换了
T& operator[](size_t i) { return *(T*)&buffer[i*sizeof(A)]; }
带有
T* operator[](size_t i) {
if (...) {
return (T*)&buffer[i*sizeof(A)];
}
return NULL;
}
其中,...
是我知道的任何谓词,它将始终求值为true
,但编译器不够聪明,无法实现它,它将总是求值为true
。
我很好奇是否有人能在这里准确地解释编译器的想法。我使用的是gcc 4.4.3。
相关文章:
- 部分定义/别名模板模板参数
- C++中的严格别名规则和类型别名
- 如何在不违反类型别名规则的情况下解释消息负载?
- 强制转换为不相关的引用类型是否违反严格的别名规则?
- POD 类型的二进制 I/O 如何不违反别名规则
- MDSPAN 和严格的别名规则
- C++20 中的严格别名规则是否允许标准 c++ unicode 字符和下划线类型之间"reinterpret
- 在不违反严格的别名规则的情况下访问进程间共享内存中的对象
- 严格别名规则是否适用于跨函数调用
- c++11 严格别名规则是否允许通过 char *、char(&)[N],甚至 std::array<char、N> 和 -fstrict-aliasing -Wstrict-aliasi
- 已签名/未签名的别名规则是否按预期工作
- 严格的别名规则可以
- 从char数组中强制转换*时,严格的别名规则是什么
- 严格的别名规则和新位置
- 使用指针转换来存储/转换值:我打破了严格的别名规则吗
- 这真的违反了严格别名规则吗?
- 取消引用类型的punned指针将打破严格的别名规则[-Wstrict aliasing]
- 指针别名规则的应用(指向自身地址的指针)
- 将char[]强制转换为usingned int给出:取消引用类型的punned指针将打破严格的别名规则
- 绕过c++严格的别名规则