ABICTの使用は安全です。
- タイプTのオブジェクトをnewに配置すると、渡されたアドレスから始まるオブジェクトが作成されます。
§5.3.4/10は言う:
new-expressionは、要求されたスペースの量をstd::size_t型の最初の引数として割り当て関数に渡します。その引数は、作成されるオブジェクトのサイズ以上でなければなりません。オブジェクトが配列である場合にのみ、作成されるオブジェクトのサイズよりも大きくなる可能性があります。
非配列オブジェクトの場合、割り当てられるサイズはオブジェクトのサイズより大きくすることはできないため、オブジェクトの表現は、収まるように割り当てられたメモリの先頭から開始する必要があります。
配置newは、「割り当て」の結果として渡されたポインタ(§18.6.1.3/ 2を参照)を返すため、構築されたオブジェクトのオブジェクト表現はそのアドレスから始まります。
static_cast<>
T*
オブジェクトが完全なオブジェクトである場合、タイプ間の暗黙的な変換とvoid*
、オブジェクトへのポインターとそのストレージへのポインターの間の変換。
§4.10/2は言う:
タイプ「pointertocvT」(Tはオブジェクトタイプ)のprvalueは、タイプ「pointertocvvoid」のprvalueに変換できます。「pointertocvT」を「pointertocvvoid」に変換した結果は、オブジェクトがタイプTの最も派生したオブジェクト(1.8)であるかのように、タイプTのオブジェクトが存在する保管場所の開始点を示します。 [...]
これは、述べられているように変換する暗黙の変換を定義します。さらに§5.2.9[expr.static.cast]/4はstatic_cast<>
、明示的な変換を定義します。暗黙的な変換は、暗黙的な変換と同じ効果を持つように存在します。
それ以外の場合、宣言
が整形式であれば、発明された一時変数(8.5)の場合、式は形式の
aを使用してe
明示的に型に変換できます。このような明示的な変換の効果は、宣言と初期化を実行し、変換の結果として一時変数を使用することと同じです。[...]T
static_cast
static_cast<T>(e)
T t(e);
t
逆static_cast<>
(fromvoid*
からT*
)の場合、§5.2.9/13は次のように述べています。
タイプ「pointertocv1void」のprvalueは、タイプ「pointer to cv2 T」のprvalueに変換できます。ここで、Tはオブジェクトタイプであり、cv2はcv1と同じかそれ以上のcv-qualificationです。[...]「cvvoidへのポインタ」に変換されたオブジェクトへのポインタ型の値は、おそらく異なるcv修飾で、元の値を持つ必要があります。
したがってvoid*
、オブジェクトのストレージを指す場合(これは、aからオブジェクトへT
の暗黙の変換から生じるポインター値であり、そのaからaへのポインターは、オブジェクトへの有効なポインターを生成します。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
最初のsize(T)バイトを正確にオーバーレイするt_
ため、pvT == pvt_
pvt_ == static_cast<void*>(&t_)
static_cast<T*>(pvT) == pT
- まとめると、
static_cast<T*>(static_cast<void*>(&t_)) == pT