2012-02-10 1 views
3

どこにC++仕様がありますか?かっこいいね。私はこれがどのように仕様化されているか知りたい。私は、未定義型へのポインタを持つことが許されている仕様であることに気づいていませんでした。C++標準では未定義の型へのポインタはどこにありますか?

class T; 

int main(int argc, char* argv[]) 
{ 
    int x; 
    T* p = reinterpret_cast<T*>(&x); 
    return 0; 
} 
+2

これはどのように許可されていますか?なぜなら、 'reinterpret_cast'は実装定義の動作か*未定義の動作です*。いずれにせよ、それは仕様によって定義されていないので、「許可」とみなせるかどうかはわかりません。それとも、前方宣言だけについて話していますか? –

+6

なぜこれはクールだろうか? – Bart

+0

@Bartあなたは厄介なことをすることができるので、多分? – tibur

答えて

4

あなたがをやっていることは法的こと、それはclass Tの実際の定義に依存するため、我々はあなたが示したコードに基づいて確実に知ることができないことがあります。 C++ 11§3.9.2/ 3以降

:彼らと何ができるかに制限があるが、不完全型への

ポインタが許可されています。

これらの制限事項は、§3に記載されています。2/4:

場合種類Tが完了しなければならないクラス:

  • タイプTのオブジェクトが定義され、又は
  • タイプTの非静的クラスのデータメンバが宣言され、または
  • TはLVA 新しい発現、又は
  • のオブジェクトタイプまたは配列要素のタイプとして使用されますLUEは対右辺値変換タイプTのオブジェクトを参照glvalueに適用される、または
  • 発現はT、又は
  • ヌルポインタ定数ではない式を入力する(暗黙的または明示的に)変換されます。 、および暗黙的な変換を使用してTTまたは参照に型ポインタに変換され、void*以外の型であり、クラスメンバアクセス演算子がタイプTの式に適用されるdynamic_cast又はstatic_cast、又は
  • 、又は
  • typeidオペレータ又はsizeofオペレータは、タイプTのオペランドに適用される、または
  • 戻り型または型 Tの引数の型を持つ関数を定義または呼ばれ
  • 、又は
  • タイプのベース・クラスとクラスTであるれます定義された、または
  • タイプTの左辺値は、Tを有する例外宣言に割り当てられた、又は
  • タイプTalignof式の主題である、又は
  • れますTTへの参照、またはTへのポインタ。

我々はポインタ型の間reinterpret_caststatic_castの用語で定義されていることを§5.2.10/ 7に見ることができるように第六弾丸は、ここに適切に表示されます。

オブジェクトポインタ明示的に別の型のオブジェクトポインタに変換することができます。タイプのprvalue vT1へのポインタを」タイプ「CV T2へのポインタ」に変換されるときT1T2両方が標準レイアウトタイプであり、T2の位置合わせ要件がT1のものよりも厳しくない場合、結果はstatic_cast<cv T2*>(static_cast<cv void*>(v))ありますいずれかのタイプがvoidの場合「T1へのポインタ」タイプのPR値をタイプ「T2へのポインタ」(T1およびT2がオブジェクトタイプであり、のアラインメント要件がT1よりも厳しくない)に変換し、元のタイプに戻すと、ポインタ値。そのような他のポインタ変換の結果は不特定である。

しかし、第六弾が適用されないことを、最初void*reinterpret_caststatic_castのため、実際の結果のポインタ型へ、その後

Tが不完全なタイプであるにもかかわらず、これまでのところ法的領域にあります。しかし、Tが標準レイアウトタイプではないか、またはintよりも厳密な位置合わせ要件を持っていると判明した場合、5.2.10/7の最後の文が真であり、あなたはUBを呼び出しています。

2

あなたのケースについては、セクション5.2.10(7)(ISO/IEC14882のように:1998(E)と同様に、2011 FDISで)。

4

無関係な型(char*以外)へのポインタをキャストした後で許可されているのは、元のポインタ型にキャストされます。

@cli_hltはセクションを提供することに私を打ち負かしました。

ここでルールそのものです:

オブジェクトポインタが明示的に異なるタイプのオブジェクトポインタに変換することができます。 タイプのprvalue vT1へのポインタを」タイプ「cvT2へのポインタ」に変換される場合T1T2両方が標準レイアウトタイプ(3.9)であり、T2の位置合わせ要件がある場合、結果はstatic_cast<cv T2*>(static_cast<cv void*>(v))ありますT1よりも厳密でないか、いずれかのタイプがvoidの場合。型に型 のprvalue「T1へのポインタを」変換「T2へのポインタ」(T1T2がオブジェクト型であり、ここでT2の位置合わせ要件がT1のものよりも厳しくない場合)と元の形にすると、得られます元のポインタ値。そのような他のポインタ変換の結果は不特定である。

厳密なエイリアシング規則は無関係タイプを介してオブジェクトへのアクセスを禁止します。 https://stackoverflow.com/a/7005988/103167

あなたの質問に幾分関連するもう一つのルールはセクション5.4で発見された参照してください:

キャスト表記を使用して、キャストのオペランドがタイプ「不完全なクラス型へのポインタ」のprvalueすることができます。 キャスト表記を使用するキャストの宛先タイプは「不完全なクラスタイプへのポインタ」になる可能性がありますオペランドタイプと宛先タイプの両方がクラスタイプで、どちらかまたは両方が不完全な場合は、static_castまたはreinterpret_cast解釈が使用されているかどうかは不明ですたとえ2つのクラスの間に継承関係 があっても

0

私はあなたが許可されていると考えているか分かりません。 1つのポインタタイプから十分に大きな他のポインタタイプへのreinterpret_castの可能性があり、再び元のタイプに戻って元のポインタになるという保証があります。この仕様は5.2.10 [expr.reinterpret.cast]にあります。それは、次のように動作することが保証されている:

T* ptr = ...; 
S* sptr = reinterpret_cast<S*>(ptr); 
T* tptr = reinterpret_cast<T*>(sptr); 
assert(ptr == tptr); 

私たちは、このトピックに今週初めセッションの議論のうちを持っていた:死ステーション9000の実装ならばCの適合実装されるであろう(++もしようとしますプログラムの実行開始時にランダムに選択されたビットパターンでポインタのビットパターンをXORすると、reinterpret_cast<T>(x)に含まれる型がcharに含まれていない場合、これは許容される実装になります。コンセンサスはこれがOKであろうということでした。

+0

私は今、私の質問が分かりません。私は、未定義型へのポインタを持つことが許されている仕様であることに気づいていませんでした。 – Mike

+0

また、私の 'reinterpret_cast <>()'が間違った型を使用していることに気付きました!私はこれを2番目に修正します(混乱を招いて申し訳ありません)。「S」と「T」は2つのレイアウト互換型であり、キャストで使用されることを意図しています。 –

関連する問題