Note that there are some explanatory texts on larger screens.

plurals
  1. POPassing null pointer to placement new
    primarykey
    data
    text
    <p>The default placement <code>new</code> operator is declared in 18.6 [support.dynamic] ¶1 with a non-throwing exception-specification:</p> <pre><code>void* operator new (std::size_t size, void* ptr) noexcept; </code></pre> <p>This function does nothing except <code>return ptr;</code> so it is reasonable for it to be <code>noexcept</code>, however according to 5.3.4 [expr.new] ¶15 this means that the compiler must check it doesn't return null before invoking the object's constructor:</p> <blockquote> <p>-15-<br> [<em>Note:</em> unless an allocation function is declared with a non-throwing exception-specification (15.4), it indicates failure to allocate storage by throwing a <code>std::bad_alloc</code> exception (Clause 15, 18.6.2.1); it returns a non-null pointer otherwise. If the allocation function is declared with a non-throwing exception-specification, it returns null to indicate failure to allocate storage and a non-null pointer otherwise. <em>—end note</em>] If the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null.</p> </blockquote> <p>It seems to me that (specifically for placement <code>new</code>, not in general) this null check is an unfortunate performance hit, albeit small.</p> <p>I've been debugging some code where placement <code>new</code> was being used in a very performance-sensitive code path to improve the compiler's code generation and the check for null was observed in the assembly. By providing a class-specific placement <code>new</code> overload that is declared with a throwing exception-specification (even though it can't possibly throw) the conditional branch was removed, which also allowed the compiler to generate smaller code for the surrounding inlined functions. The result of saying the placement <code>new</code> function <em>could</em> throw, even though it <em>couldn't</em>, was measurably better code.</p> <p>So I've been wondering whether the null check is really required for the placement <code>new</code> case. The only way it can return null is if you pass it null. Although it's possible, and apparently legal, to write:</p> <pre><code>void* ptr = nullptr; Obj* obj = new (ptr) Obj(); assert( obj == nullptr ); </code></pre> <p>I can't see why that would be useful, I suggest it would be better if the programmer had to check for null explicitly before using placement <code>new</code> e.g.</p> <pre><code>Obj* obj = ptr ? new (ptr) Obj() : nullptr; </code></pre> <p>Has anyone ever needed placement <code>new</code> to correctly handle the null pointer case? (i.e. without adding an explicit check that <code>ptr</code> is a valid memory location.)</p> <p>I'm wondering whether it would be reasonable to forbid passing a null pointer to the default placement <code>new</code> function, and if not whether there is some better way to avoid the unnecessary branch, other than trying to tell the compiler the value is not null e.g.</p> <pre><code>void* ptr = getAddress(); (void) *(Obj*)ptr; // inform the optimiser that dereferencing pointer is valid Obj* obj = new (ptr) Obj(); </code></pre> <p>Or:</p> <pre><code>void* ptr = getAddress(); if (!ptr) __builtin_unreachable(); // same, but not portable Obj* obj = new (ptr) Obj(); </code></pre> <p><strong>N.B.</strong> This question is intentionally tagged micro-optimisation, I am <strong>not</strong> suggesting that you go around overloading placement <code>new</code> for all your types to "improve" performance. This effect was noticed in a very specific performance-critical case and based on profiling and measurement.</p> <p><strong>Update:</strong> <a href="http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1748">DR 1748</a> makes it undefined behaviour to use a null pointer with placement new, so compilers are no longer required to do the check.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload