Mixing operator new[] and placement new with ordinary delete[]

前端 未结 5 2083
悲&欢浪女
悲&欢浪女 2020-12-18 20:10

Just out of curiosity, is the following legal?

X* p = static_cast(operator new[](3 * sizeof(X)));
new(p + 0) X();
new(p + 1) X();
new(p + 2) X();

         


        
5条回答
  •  旧巷少年郎
    2020-12-18 20:17

    From 5.3.5 [expr.delete] in n3242:

    2

    [...]

    In the second alternative (delete array), the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression. If not, the behavior is undefined. [...]

    which means that for delete[] p, p must have been the result of something of the form new[] p (a new expression), or 0. Seeing as the result of operator new is not listed here, I think the first case is right out.


    I believe the second case is Ok. From 18.6.1.2 [new.delete.array]:

    11

    void operator delete[](void* ptr) noexcept;

    [...]

    Requires: ptr shall be a null pointer or its value shall be the value returned by an earlier call to operator new or operator new[](std::size_t,const std::nothrow_t&) which has not been invalidated by an intervening call to operator delete. [...]

    (there is similar text in 3.7.4.2 [basic.stc.dynamic.deallocation], paragraph 3)

    So as long as the de/allocation functions match (e.g. delete[] (new[3] T) is well-formed) nothing bad happens. [ or does it? see below ]


    I think I tracked the normative text of what Jerry is warning about, in 5.3.4 [expr.new]:

    10

    A new-expression passes the amount of space requested to the allocation function as the first argument of type std::size_t. That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array. [...]

    Following in the same paragraph is an example (so non-normative) which underlines that the new expressions of an implementation are indeed free to ask more from the allocation function than the space the array takes (storing the optional std::size_t parameter available to deallocation function comes to mind), and that they can offset into the result. So all bets are off in the array case. The non-array case seems fine though:

    auto* p = new T;
    // Still icky
    p->~T();
    operator delete(p);
    

提交回复
热议问题