【问题标题】:Placement new in std::aligned_storage?std::aligned_storage 中的新位置?
【发布时间】:2015-03-27 02:04:01
【问题描述】:

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

假设我有一个std::aligned_storage,如下所示:

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

我想将新的 T 放入 storage

传递给placement new 运算符的符合标准的指针值/类型是什么,我如何从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));

以上哪项(如果有)符合要求,如果没有,更好的方法是什么?

【问题讨论】:

    标签: c++ c++14


    【解决方案1】:

    最偏执的方式是

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

    解释:

    • ::std::addressof 防止 storage 上的一元 operator&amp; 过载,这在技术上是标准允许的。 (尽管没有理智的实现会这样做。)::std 可以防止任何可能在范围内的名为 std 的非顶级命名空间(或类)。
    • (void *)(在这种情况下相当于 static_cast)确保您调用展示位置 operator new 时采用 void * 而不是像 decltype(storage) * 这样的其他名称。
    • ::new 跳过任何特定于类的放置 operator news,确保调用转到全局位置。

    这共同保证了调用会转到库放置 operator new 并采用 void *,并且 T 是在 storage 所在的位置构造的。

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

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

    应该足够了。

    【讨论】:

    • 好的,+1 表示偏执狂的程度。如果我开始编写 Hell++ 实现,我会请你合作:-)
    • @Nikos 见stackoverflow.com/a/332086/1896169。 "[C-style casts] 被定义为以下成功的第一个:const_caststatic_cast(尽管忽略访问限制)、static_cast(见上文)然后是const_castreinterpret_cast、@987654345 @ 然后const_cast"
    【解决方案2】:

    放置分配函数描述如下(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&lt;Len, Align&gt;,因此:

    成员 typedef type 应为适合使用的 POD 类型 作为任何对象的未初始化存储 其大小最多为 Len 并且其 对齐是对齐的除数。

    这意味着在您的情况下,&amp;storage 已适当对齐以容纳 T 类型的对象。因此,在正常情况下1,您列出的调用placement new 的所有4 种方式都是有效且等效的。为简洁起见,我会使用第一个 (new (&amp;storage))。


    1在 cmets 中正确指出,从技术上讲,您的程序可以声明采用 typename std::aligned_storage&lt;sizeof(T), alignof(T)&gt;::type* 的分配函数的重载,然后通过重载决议而不是库提供的“放置新”版本来选择它。

    我会说这在至少 99.999% 的情况下不太可能,但如果您也需要防范这种情况,请使用 void* 中的一种。直接static_cast&lt;void*&gt;(&amp;storage)就够了。

    另外,如果您对这种程度的偏执,您可能应该使用::new 而不是仅仅使用new 来绕过任何特定于类的分配函数。

    【讨论】:

    • 只有带有void* 演员表的版本才能保证进入新的库放置。
    • 另外,为了更加偏执,::new
    猜你喜欢
    • 2013-10-18
    • 2016-02-12
    • 2013-03-05
    • 1970-01-01
    • 2015-08-31
    • 2019-02-19
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多