I'm currently using aligned_storage to implement an 'Optional' type similar to that of boost::optional. To accomplish this I have a class member like so:
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type t_;
I use placement new to create the object, however I don't store the pointer returned anywhere. Instead, I access the underlying type of the object in all my member functions like this (obviously with checks to ensure the object is valid via a boolean flag also stored in my Optional type):
T const* operator->() const {
return static_cast<T const*>(static_cast<void const*>(&t_));
}
My question is whether this is safe. My understanding is that my usage of placement new changes the 'dynamic type' of the object, and as long as I keep accessing the memory using that type I'll be okay. However I'm not clear on whether I have to hold the pointer returned from the placement new or whether I'm allowed to just cast to the underlying type whenever I need to access it. I have read section 3.10 of the C++11 standard, however I'm not fluent enough in standardese to be sure.
If possible, I would feel better if you could give reference to the standard in your answer (it helps me sleep at night :P).
ABICT your use is safe.
§5.3.4/10 says:
For a non-array object, the size allocated cannot be greater that the size of the object, so the object representation must start at the beginning of the allocated memory in order to fit.
Placement new returns the pointer passed in (see § 18.6.1.3/2) as the result of the "allocation", so the object representation of the constructed object will start at that address.
static_cast<>
and implicit conversions betweenT*
type andvoid*
convert between a pointer to the object and a pointer to its storage, if the object is a complete object.§4.10/2 says:
This defines the implicit conversion to convert as stated. Further §5.2.9[expr.static.cast]/4 defines
static_cast<>
for explicit conversions, where an implicit conversion exists to have the same effect as the implicit conversion:For the inverse
static_cast<>
(fromvoid*
toT*
), §5.2.9/13 states:So if you have a
void*
pointing to the storage of theT
object (which is the pointer value that would result from the implicit conversion of aT*
to the object, then astatic_cast
of that to aT*
will produce a valid pointer to the object.Returning to your question, the preceding points imply that if you have
then
*pT
exactly overlays the first size(T) bytes of the storage oft_
, so thatpvT == pvt_
pvt_ == static_cast<void*>(&t_)
static_cast<T*>(pvT) == pT
static_cast<T*>(static_cast<void*>(&t_)) == pT