Ответ 1
ПОЖАЛУЙСТА, ваше использование безопасно.
- Размещение нового объекта типа T создаст объект, начинающийся с переданного адреса.
В §5.3.4/10 говорится:
Новое выражение передает объем пространства, запрошенный для функция распределения как первый аргумент типа std:: size_t. Что аргумент должен быть не меньше размера создаваемого объекта; он может быть больше размера создаваемого объекта, только если объект представляет собой массив.
Для объекта без массива назначенный размер не может быть больше размера объекта, поэтому представление объекта должно начинаться в начале выделенной памяти, чтобы оно соответствовало.
Размещение нового возвращает переданный указатель (см. § 18.6.1.3/2) в результате "выделения", поэтому представление объекта построенного объекта начнется с этого адреса.
-
static_cast<>
и неявные преобразования междуT*
type иvoid*
конвертировать между указателем на объект и указателем на его хранилище, если объект является полным объектом.
В §4.10/2 говорится:
Значение типа "указатель на cv T", где T - тип объекта, может быть преобразован в prvalue типа "указатель на cv void" . Результат преобразование "указателя на cv T" в "указатель на cv void" указывает на начало места хранения, где находится объект типа T, так как если объект является наиболее производным объектом (1.8) типа T [...]
Это определяет неявное преобразование для преобразования, как указано. Далее §5.2.9 [expr.static.cast]/4 определяет static_cast<>
для явных преобразований, где существует неявное преобразование, чтобы иметь тот же эффект, что и неявное преобразование:
В противном случае выражение
e
может быть явно преобразовано в типT
используяstatic_cast
формыstatic_cast<T>(e)
, если декларацияT t(e);
является корректным, для некоторой изобретенной временной переменнойT
(8.5). Эффект такого явного преобразования такой же, как и выполнение декларации и инициализации, а затем используя временную переменная в результате преобразования. [...]
Для обратного static_cast<>
(от void*
до T*
) в §5.2.9/13 говорится:
Значение типа "указатель на cv1 void" может быть преобразовано в prvalue типа "указатель на cv2 T", где T - тип объекта, а cv2 - такая же CV-квалификация, как или более высокая cv-квалификация, чем cv1. [...] Значение указателя типа на объект, преобразованный в "указатель на cv void" и обратно, возможно с другой cv-квалификацией, должны иметь оригинальное значение.
Итак, если у вас есть void*
, указывающий на хранилище объекта T
(который является значением указателя, которое будет результатом неявного преобразования T*
в объект, тогда static_cast
этого до T*
будет выдавать действительный указатель на объект.
Возвращаясь к вашему вопросу, предыдущие пункты подразумевают, что если у вас
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type t_;
void * pvt_ = &t_;
T* pT = new (&t_) T(args...);
void * pvT = pT;
то
- хранилище
*pT
точно накладывает байты первого размера (T) хранилищаt_
, так чтоpvT == pvt_
-
pvt_ == static_cast<void*>(&t_)
-
static_cast<T*>(pvT) == pT
- Взято вместе, что дает
static_cast<T*>(static_cast<void*>(&t_)) == pT