std::aligned_storage 中的新位置?

Placement new in std::aligned_storage?

假设我有一个类型模板参数 T。

假设我有一个 std::aligned_storage 如下:

typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;

我想将新的 T 放入 storage

传递给放置新运算符的符合标准的指针 value/type 是什么,我如何从 storage 导出它?

new (& ???) T(a,b,c);

例如:

new (&storage) T(a,b,c);
new (static_cast<void*>(&storage)) T(a,b,c);
new (reinterpret_cast<T*>(&storage)) T(a,b,c);
new (static_cast<T*>(static_cast<void*>(&storage));

以上哪项(如果有)是合规的,如果none,更好的方法是什么?

放置分配函数说明如下(C++14 n4140 18.6.1.3):

void* operator new(std::size_t size, void* ptr) noexcept;

Returns: ptr.

Remarks: Intentionally performs no other action.

20.10.7.6 table 57 描述 aligned_storage<Len, Align> 因此:

The member typedef type shall be a POD type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.

这意味着在您的情况下,&storage 适合对齐 T 类型的对象。因此,在正常情况下1,您列出的调用放置的4种方式new都是有效且等价的。为了简洁起见,我会使用第一个 (new (&storage))。


1T.C。在评论中正确指出,您的程序在技术上可以声明采用 typename std::aligned_storage<sizeof(T), alignof(T)>::type* 的分配函数的重载,然后通过重载决议而不是库提供的 'placement new' 版本来选择.

我会说这在至少 99.999% 的情况下不太可能发生,但如果您也需要防范这种情况,请对 void* 使用其中一种强制转换。直接static_cast<void*>(&storage)就够了

此外,如果您偏执到这个程度,您可能应该使用 ::new 而不是 new 来绕过任何 class 特定的分配函数。

最偏执的方式是

::new ((void *)::std::addressof(storage)) T(a, b, c);

解释:

  • ::std::addressof 防止在 storage 上重载一元 operator&,这在技术上是标准允许的。 (尽管没有任何理智的实现会这样做。)::std 防止任何可能在范围内的名为 std 的非顶级命名空间(或 classes)。
  • (void *)(在本例中等同于 static_cast)确保您调用展示位置 operator new 采用 void * 而不是其他类似 decltype(storage) *.
  • ::new 跳过任何 class 特定位置 operator new,确保调用转到全局位置。

一起,这保证了调用进入库放置 operator new 采取 void *,并且 Tstorage 所在的位置构造。

不过,在大多数理智的程序中,

new (&storage) T(a,b,c);

应该足够了。