假设我有一个类型模板参数T.
假设我有std::aligned_storage
如下:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
我想将新的T放入storage
。
要传递给贴牌新操作符的符合标准的指针值/类型是什么?如何从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));
上述哪一项(如果有的话)是合规的,如果没有,那么更好的方法是什么?
答案 0 :(得分:44)
最偏执的方式是
::new ((void *)::std::addressof(storage)) T(a, b, c);
说明:
::std::addressof
防范operator&
上的重载一元storage
,这在标准上是技术上允许的。 (虽然没有理智的实现会这样做。)::std
防范任何可能在范围内的名为std
的非顶级名称空间(或类)。(void *)
(在这种情况下相当于static_cast
)确保您调用展示位置operator new
取void *
而不是decltype(storage) *
}}。::new
会跳过任何特定于课程的展示位置operator new
,以确保通话能够转到全球展示位置。这样可以保证调用将operator new
放置到void *
的{{1}},T
的位置storage
。{/ p} >
在大多数理智的程序中,
new (&storage) T(a,b,c);
应该足够了。
答案 1 :(得分:4)
放置分配功能描述如下(C ++ 14 n4140 18.6.1.3):
void* operator new(std::size_t size, void* ptr) noexcept;
返回:
ptr
。备注:故意不执行任何其他操作。
20.10.7.6表57描述了aligned_storage<Len, Align>
因此:
成员typedef
type
应为适合使用的POD类型 作为任何对象的未初始化存储 其大小最多为 Len alignment是 Align的除数。
这意味着在您的情况下,&storage
适合对齐以保存T
类型的对象。因此,在正常情况下 1 ,您列出的调用展示位置new
的所有4种方式都是有效且等效的。为简洁起见,我会使用第一个(new (&storage)
)。
1 T.C.在评论中正确地指出,你的程序在技术上可以使用typename std::aligned_storage<sizeof(T), alignof(T)>::type*
来声明分配函数的重载,然后通过重载决策而不是库提供的&#39;放置新的& #39;版本
我认为这至少在99.999%的情况下不太可能,但如果你需要防范这种情况,请使用其中一个强制转换为void*
。直接static_cast<void*>(&storage)
就足够了。
另外,如果你偏执到这个级别,你应该使用::new
而不是new
来绕过任何特定于类的分配函数。