N3337 的basic.stc.dynamic.allocation/2(基本上是C++11):
分配函数尝试分配请求的数量
贮存。成功则返回起始地址
一个存储块,其字节长度至少应该一样大
作为要求的大小。内容没有限制
从分配函数返回时分配的存储空间。命令,
连续性和连续调用分配的存储的初始值
分配函数是未指定的。 返回的指针应
适当对齐,以便它可以转换为任何指针
具有基本对齐要求的完整对象类型 (3.11)
然后用于访问分配的存储中的对象或数组
(直到通过调用
相应的释放函数)。即使空间大小
请求为零,请求可能失败。如果请求成功,则
返回的值应为非空指针值 (4.10) p0 不同
从任何先前返回的值 p1,除非该值 p1 是
随后传递给操作员删除。取消引用的影响
作为零大小请求返回的指针未定义。
基本对齐 (basic.align/2):
基本对齐由小于或的对齐表示
等于实现支持的最大对齐
所有上下文,等于 alignof(std::max_align_t)
扩展对齐(basic.align/3):
扩展对齐由大于的对齐表示
alignof(std::max_align_t)。
是否有任何扩展对齐是由实现定义的
支持以及支持它们的上下文
因此,operator new 返回的指针必须具有基本对齐。即使指定了零大小。它是实现定义的,无论 8 是基本对齐还是扩展对齐。如果它是基本的,那么Foo 是可以的。如果它被扩展,那么它是实现定义Foo支持operator new。
注意,对于 C++17,情况有所改善:
basic.stc.dynamic.allocation/2 of C++17:
分配函数尝试分配请求的数量
贮存。成功则返回起始地址
一个存储块,其字节长度至少应该一样大
作为要求的大小。内容没有限制
从分配函数返回时分配的存储空间。命令,
连续性和连续调用分配的存储的初始值
分配函数是未指定的。 返回的指针应
适当对齐,以便可以将其转换为指向任何
合适的完整对象类型([new.delete.single]),然后用于
访问分配的存储中的对象或数组(直到存储
通过调用相应的解除分配显式解除分配
功能)。即使请求的空间大小为零,
请求可能会失败。如果请求成功,返回值应为
一个非空指针值 ([conv.ptr]) p0 不同于以前的任何
返回值 p1,除非该值 p1 随后被传递给
运算符删除。此外,对于库分配函数
[new.delete.single] 和 [new.delete.array],p0 代表
与任何其他存储不相交的存储块的地址
调用者可访问的对象。通过一个间接的效果
作为零大小请求返回的指针未定义。
我已经把重点放在了相关部分。那句话的意思是void *operator new(...)的返回指针应该有合适的对齐方式。它没有提到零大小作为特例(但是,当然,取消引用返回的指针是 UB)。
所以答案是平常的,没有对零的特殊处理:
-
void *operator new(std::size_t) 必须返回 alignof(std::max_align_t) 的对齐指针
-
void *operator new(std::size_t, std::align_val_t align) 必须返回一个对齐的指针 align)
请注意,它是实现定义的,将为Foo 调用哪个版本。这取决于 8 是否等于或小于alignof(std::max_align_t)。如果小于,则调用第一个版本(因为它没有扩展对齐)。否则调用第二个。
更新:作为 Massimiliano Janes cmets,这些段落适用于 operator new 的结果,而不适用于新表达式的结果。实现可以向operator new[] 的结果添加任意偏移量。并且标准对这个x 偏移量的值保持沉默:
new T[5] 会导致以下调用之一:
算子 new[](sizeof(T) * 5 + x)
运算符 new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)))
这里,x 的每个实例都是一个非负的未指定值
表示数组分配开销;的结果
new-expression 将从返回的值偏移这个量
通过运算符 new[]。此开销可应用于所有阵列
新表达式,包括那些引用库函数的表达式
operator new[](std::size_t, void*) 和其他布局分配
职能。开销的数量可能与一次调用 new 不同
到另一个。
但是,在我看来,这个x 偏移量不能是任意的。如果它不是对齐的倍数,那么新表达式将返回一个非对齐指针(在所有情况下。不仅是零,还有非零大小参数)。这显然不是我们想要的。
所以我认为这是标准中的一个漏洞。 x 的值应限制为对齐的倍数(至少在非零分配情况下)。但是由于这个遗漏,标准似乎不能保证new[] 表达式完全返回对齐的指针(在非零情况下也是如此)。