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 *
,并且 T
在 storage
所在的位置构造。
不过,在大多数理智的程序中,
new (&storage) T(a,b,c);
应该足够了。
假设我有一个类型模板参数 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 *
,并且 T
在 storage
所在的位置构造。
不过,在大多数理智的程序中,
new (&storage) T(a,b,c);
应该足够了。