Consider the following C++14 code:
#include <cassert> #include <new> #include <type_traits> struct NonStandardLayout { // ... }; int main() { using T = NonStandardLayout; std::aligned_storage_t< sizeof(T), alignof(T) > storage; T *const valid_ptr = new(static_cast<void *>(&storage)) T; T *const maybe_ptr = reinterpret_cast<T *>(&storage); assert(maybe_ptr == valid_ptr); // ??? valid_ptr->T::~T(); return 0; }
Is it guaranteed by the standard that the assert in the example will never fail, for any type T?
Looking in the latest standard (http://eel.is/c++draft/), I cannot see any reference to this particular scenario but I have found the following paragraphs that arguably points to the answer 'yes'.
Is it correct of me to think that [expr.new/15] and [new.delete.placement/2] together states that the value of valid_ptr
will equal the address of storage
, always?
If so, is it true that the reinterpret_cast
will yield a pointer to a fully constructed object? Because, [expr.reinterpret.cast/7], [expr.static.cast/13] and [basic.compound/4] together seem to indicate that it should be the case.
From my observations, library implementations of the default allocator seem to cast similar to this and without worry! Is it really safe to cast like this?
How can we be sure that the two pointers will be the same, or can we?
It is unambiguously specified that the placement new operator returns whatever pointer is passed to it.
Placement new is a variation new operator in C++. Normal new operator does two things : (1) Allocates memory (2) Constructs an object in allocated memory. Placement new allows us to separate above two things. In placement new, we can pass a preallocated memory and construct an object in the passed memory.
A placement new expression first calls the placement operator new function, then calls the constructor of the object upon the raw storage returned from the allocator function.
I'm surprised no one has mentioned this cheap counterexample yet:
struct foo { static foo f; // might seem dubious but doesn't violate anything void* operator new(size_t, void* p) {return &f;} };
Demo on Coliru.
Unless a class-specific placement version is called, however, your assertion should hold. Both expressions have to represent the same address as explained in the other answer (the main point being that the standard non-allocating operator new
simply returns the pointer argument and the new expression not doing anything fancy), and neither of these is a pointer past the end of some object so, by [expr.eq]/2, they compare equal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With