Astd::vector<char>
包含指向某个堆分配缓冲区的指针。
考虑到内存对齐问题,内存分配返回的分配缓冲区是否保证仅针对类型正确对齐char
,或者是否会对齐到某些常见值,例如 4 或 8 个字节?(或者未指定?)
举例来说,默认分配器是new
。调用new
可能会返回任意内存地址。但它真的是任意的吗?
- 也许在 64 位机器上它是 8 字节对齐的?
T
也许它与所使用的类型一致std::vector<T>
?(这似乎是最有可能的选项。)- 也许返回的地址是任意的,可以是任何值。(我不认为这是正确的。)
- 还有别的吗?
问这个问题的原因是我想知道我是否可以安全地将这块内存中包含的字节重新解释为其他类型,例如float
,,,等等。double
uint64_t
从另一个角度看,情况更加明显。(我认为——请纠正我。)
例如,如果我们要求一个std::vector<uint64_t>
,那么内存分配返回的、由对象持有的指针std::vector
将是 8 字节对齐的。
因此,以如下方式读写数据是安全的:
char*
- 正确对齐(4字节对齐)
float
- 正确对齐(8字节)
double
- 正确对齐(2字节)
unsigned short int
- ... ETC
但是,如果的分配std::vector<char>
可以返回 (十进制) 的内存地址1025
,那么如果重新解释为任何大于 1 字节宽的类型,显然不能保证在任何偏移量处正确对齐。
我认为我的理解是正确的,但是如果其中任何一点不太合理或者不正确,请在评论中告诉我。
编辑:
我可能已经找到了答案,但我不确定如何解释我所读到的内容。
从:
此函数需要返回一个适当对齐的指针,以指向请求大小的对象。
但这是什么意思呢?
对于宽度为 1 字节的对象,这似乎表明任何地址值都是可以接受的。
对于宽度为 2 字节的对象,建议任何偶数值地址都是可以接受的。
对于 4 个字节,为 4 的任意倍数。对于 8 个字节,为 8 的任意倍数。
但是其他值呢?据我所知,x86 中没有从内存加载 3 字节值的指令。如果您请求3 字节宽的值new[T]
在哪里,会发生什么?T
struct
虽然从技术上来说这似乎无法保证,但我相当肯定没有任何实现能够给你一个来自的未对齐指针
std::vector<char>
。默认
operator new
返回与对齐的内存__STDCPP_DEFAULT_NEW_ALIGNMENT__
,虽然我找不到任何保证来证明这一点>= alignof(std::max_align_t)
,但任何合理的实现都会这样做。还有一个版本需要
operator new
,std::align_val_t
虽然它的目的是支持更大的对齐,但不能保证std::allocator
不会为更小的对齐调用它,尽管明智的实现可能不会这样做,或者如果它会这样做,调用仍然会至少确保__STDCPP_DEFAULT_NEW_ALIGNMENT__
对齐。我之所以期望这在实践中可行,很大程度上是因为
std::align_val_t
和过度对齐operator new
是最近在 C++17 中添加的。在此之前,您必须让__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= alignof(std::max_align_t)
才能new
正常运作,并且std::vector<char>
必须给您一个至少与 对齐的指针__STDCPP_DEFAULT_NEW_ALIGNMENT__
,因此我怀疑实现会突然放弃这一保证。