cppreference† 次のように述べています:
簡単なデフォルトコンストラクターを持つオブジェクトは、適切に調整されたストレージで
reinterpret_cast
を使用して作成できます。std::malloc
で割り当てられたメモリ上。
これは、以下が明確に定義されたコードであることを意味します。
struct X { int x; };
alignas(X) char buffer[sizeof(X)]; // (A)
reinterpret_cast<X*>(buffer)->x = 42; // (B)
次の3つの質問があります。
X
の存続期間はいつ始まりますか?行(B)
の場合、ストレージの取得と見なされるのはキャスト自体ですか?行(A)
の場合、(A)
と(B)
の間に、X
または他のポッドY
を条件付きで構築するブランチがあるとどうなりますか?†これは古いリンクであることに注意してください。この質問に答えて表現が変更されました。それは今読みます:
ただし、Cとは異なり、
std::malloc
で割り当てられたメモリなど、適切に配置されたストレージを再解釈するだけでは、簡単なデフォルトコンストラクターを持つオブジェクトを作成できません。新しいオブジェクトを正式に導入し、未定義の動作の可能性を回避するには、placement-newが必要です。
生きているかどうかにかかわらず、X
オブジェクトは存在しないため、1つのオブジェクトがあると偽って、未定義の動作が発生します。
[intro.object]/1 オブジェクトが作成されたときに徹底的にスペルアウトします:
objectは、定義([basic.def])によって、new-expression([expr.new])によって作成されます。 union([class.union])、または一時オブジェクトが作成されたとき([conv.rval]、[class.temporary])。
P0137R1 の採用により、この段落は「オブジェクト」という用語の定義です。
X
オブジェクトの定義はありますか?いいえ。new-expressionはありますか?いいえ。組合はありますか?いいえ。一時的なX
オブジェクトを作成する言語構成がコードにありますか?番号。
[basic.life]が空の初期化を持つオブジェクトの寿命について何を言っていても関係ありません。それを適用するには、最初にオブジェクトが必要です。あなたはしません。
C++ 11にもほぼ同じ段落がありますが、「オブジェクト」の定義としては使用しません。それにもかかわらず、解釈は同じです。代替の解釈basic.life]を適切なストレージが取得されるとすぐにオブジェクトを作成するものとして扱う-は、Schrödingerのオブジェクトを作成していることを意味します*、これは矛盾します N3337 [intro.object]/6 :
ビットフィールドではない2つのオブジェクトは、一方が他方のサブオブジェクトである場合、または少なくとも一方がサイズがゼロの基本クラスサブオブジェクトであり、タイプが異なる場合、同じアドレスを持つ可能性があります。それ以外の場合は、アドレスが異なります。
* タイプT
の適切なアラインメントとサイズのストレージは、定義により、サイズとアラインメントの要件が以下のものと等しいか、それより少ない--- [他のすべてのタイプの適切なアラインメントとサイズのストレージです。 T
。したがって、その解釈は、ストレージを取得すると、同時に同じストレージを持つさまざまなタイプのオブジェクトが無限に作成されることを意味します。
この分析はn4567に基づいており、そこからのセクション番号を使用します。
§5.2.10/ 7:オブジェクトポインタータイプのprvalue v
がオブジェクトポインタータイプ「pointer to cv T」に変換されると、結果はstatic_cast<cv T*>(static_cast<cv void*>(v))
になります。 。
したがって、この場合、reinterpret_cast<X*>(buffer)
はstatic_cast<X *>(static_cast<void *>(buffer))
と同じです。これにより、static_cast
の関連部分を確認できます。
§5.2.9/ 13:タイプ "pointer to cv1 void"のprvalueは、タイプ "pointer to cv2 T"のprvalueに変換できます。Tはオブジェクトタイプとcv2はcv1と同じcv-qualification、またはそれより大きいcv-qualificationです。 NULLポインター値は、宛先タイプのNULLポインター値に変換されます。元のポインタ値がメモリ内のバイトのアドレスA
を表し、A
がT
のアライメント要件を満たす場合、結果のポインタ値は元のポインタ値と同じアドレスを表しますポインタ値、つまりA
。
私は、元の引用がある程度正しいと言うには十分だと思います-この変換は明確な結果を与えます。
生涯に関しては、あなたが話している生涯に依存します。キャストは、ポインタ型の新しいオブジェクトを作成します。一時オブジェクトは、キャストが配置されている行から始まり、スコープから外れると終了します。条件付きで発生する2つの異なる変換がある場合、各ポインターには、それを作成したキャストの場所から始まる存続期間があります。
これらはどちらも、基になるストレージを提供するオブジェクトの存続期間には影響しません。これは、buffer
であり、そのストレージへの(同じまたは変換されたタイプの)ポインターを作成したかどうかに関係なく、存続期間はまったく同じです。ない。