7

C++でのメモリの割り当て解除について質問があります。

typedef struct type1
{
   int a;
   int b;
   float c;
} Type1;

typedef struct type2
{
   int a;
   int b;
} Type2;

void *p = new Type1;

delete (Type2 *)p;

この場合、別のサイズのタイプにキャストしたp後でも、が指しているメモリ領域は完全に削除されますか?p

4

3 に答える 3

14

動作は未定義です。この場合、動的に割り当てられたオブジェクトは、 type のポインタを介してのみ削除できますType1

まず、 によって取得さ(Type2 *)pれたポインタをdelete式で使用すると、エイリアシング ルールに違反します。指し示すオブジェクトをp使用できる型のセットは限られています。C++03 の規則は、別の質問への回答に記載されている場合があります。C++11 のルールは似ています (違いは質問への回答とは関係ありません)。

プログラムが厳密なエイリアシング規則に違反していなくても、delete式の要件に違反することになります。仕様には次のように記載されています (C++11 §5.3.5[expr.delete]/3):

削除するオブジェクトの静的型がその動的型と異なる場合、静的型は削除するオブジェクトの動的型の基本クラスであり、静的型は仮想デストラクタを持つ必要があります。そうしないと、動作が未定義になります。

式では、deleteオブジェクトの静的タイプは ですがType2、動的タイプはType1です。型は異なりますが、静的型は動的型の基本クラスではありません。

于 2013-01-02T21:33:03.053 に答える
4

Type1 ポインターで Type2::~Type2 を実行するようにコンパイラーに依頼することになり、そのデストラクタがオブジェクトの末尾を参照する可能性があるため、これは非常に悪い考えです。

従来の環境では、コンパイル時に呼び出された型を気にしないoperator delete呼び出しが行われるため、メモリの最終的な解放は問題ありません。freeただし、それほど一般的ではない環境では、災害になる可能性があります。

于 2013-01-02T21:34:19.803 に答える
0

この質問はすでにJamesによって完全に回答されていますが、1 つ指摘したいことがあります。

適切な C++ コードでは、ポインターを操作することはほとんどありません。voidつまり、コードはおそらく次のようになります。

SubType *p = new SubType;
BaseType* pB = (BaseType*)p;
delete pB;

この場合、 にBaseType適切な仮想コンストラクターがあったとしても、 がSubTypeから派生していない場合、未定義の動作が発生する可能性がありBaseTypeます。一般的な C スタイルのキャストは、ここではあまり幸運な選択ではありません。

しかし、 を使用する場合、それがポリモーフィック型のオブジェクトを指しdynamic_castていない場合、コンパイラはおそらくそれを許可しません。pそしてp、それがポリモーフィック型のオブジェクトを指しているが、BaseTypeの基本型ではないSubType場合でも、dynamic_cast返さNULLれ、この状態を適切に処理できます。

SubType *p = new SubType;
BaseType* safePtr = dynamic_cast<BaseType *>(p);
if (!safePtr) // p doesn't point to object of type derived from BaseType
    ...       // handle this situation
else          // p points to object of polymorphic type derived from BaseType
    delete safePtr;
于 2013-01-02T22:24:03.320 に答える