次のC++があるとします。
char *p = new char[cb];
SOME_STRUCT *pSS = (SOME_STRUCT *) p;
delete pSS;
これはC++標準に従って安全ですか?にキャストバックしてからchar*
使用する必要がありますdelete[]
か?デストラクタのないプレーンな通常のデータであるため、ほとんどのC++コンパイラで機能することを私は知っています。安全であることが保証されていますか?
次のC++があるとします。
char *p = new char[cb];
SOME_STRUCT *pSS = (SOME_STRUCT *) p;
delete pSS;
これはC++標準に従って安全ですか?にキャストバックしてからchar*
使用する必要がありますdelete[]
か?デストラクタのないプレーンな通常のデータであるため、ほとんどのC++コンパイラで機能することを私は知っています。安全であることが保証されていますか?
安全であるとは限りません。C ++FAQliteの関連リンクは次のとおりです。
[16.13][]
いくつかの組み込み型(、、など)の配列を削除するときにを削除char
できますint
か?
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13
いいえ、これは未定義の動作です。コンパイラはおそらく別のことを行う可能性があり、 thudbangが リンクしているC ++ FAQエントリが言うように、operator delete[]
とは異なることを行うためにオーバーロードされる可能性がありますoperator delete
。時々それを回避することができますが、それができない場合には、delete[]とnew[]を一致させる習慣を身につけることもお勧めします。
私はそれを非常に疑っています。
メモリを解放する疑わしい方法がたくさんあります。たとえば、( ではなく) 配列で使用できdelete
、おそらく正常に動作します。これについてはブログで詳しく説明しました (自己リンクで申し訳ありませんが、すべてを書き直すよりは簡単です)。char
delete[]
コンパイラはプラットフォームほど問題ではありません。ほとんどのライブラリは、基盤となるオペレーティング システムの割り当て方法を使用します。つまり、同じコードが Mac と Windows と Linux で異なる動作をする可能性があります。私はこれの例を見てきましたが、どれも疑わしいコードでした。
最も安全な方法は、常に同じデータ型を使用してメモリの割り当てと解放を行うことです。s を割り当てchar
て他のコードに返す場合は、特定の割り当て/割り当て解除メソッドを提供する方がよい場合があります。
SOME_STRUCT* Allocate()
{
size_t cb; // Initialised to something
return (SOME_STRUCT*)(new char[cb]);
}
void Free(SOME_STRUCT* obj)
{
delete[] (char*)obj;
}
( new
anddelete
演算子をオーバーロードすることも選択肢の 1 つかもしれませんが、私はこれを行うのが好きではありませんでした。)
これは私がここで答えた質問と非常によく似た質問です:リンクテキスト
要するに、いいえ、C++標準によると安全ではありません。何らかの理由で、メモリの領域にSOME_STRUCTオブジェクトを割り当てる必要がある場合は、size_of(SOME_STRUCT)
グローバルなどの生の割り当て関数を使用しoperator new
て割り当てを実行することをお勧めします。次に、プレースメントを使用してrawメモリにオブジェクトインスタンスを作成しますnew
。オブジェクト型にコンストラクタがない場合、配置new
は非常に安価になります。
void* p = ::operator new( cb );
SOME_STRUCT* pSS = new (p) SOME_STRUCT;
// ...
delete pSS;
これはほとんどの場合機能します。SOME_STRUCT
がPOD構造体の場合は、常に機能するはずです。SOME_STRUCT
コンストラクターがスローSOME_STRUCT
せず、カスタム演算子deleteがない場合も、他の場合に機能します。このテクニックはまた、キャストの必要性を排除します。
::operator new
と::operator delete
はC++に最も近いものmalloc
でありfree
、これら(クラスのオーバーライドがない場合)は適切に呼び出されnew
、delete
式は(注意して!)組み合わせて使用できます。
C++ 標準 [5.3.5.2] では次のように宣言されています。
オペランドがクラス型の場合、オペランドは前述の変換関数を呼び出すことによってポインタ型に変換され、変換されたオペランドは、このセクションの残りの部分で元のオペランドの代わりに使用されます。いずれの場合も、delete のオペランドの値はヌル ポインター値である可能性があります。null ポインター値でない場合、最初の選択肢 (delete オブジェクト) で、delete のオペランドの値は、非配列オブジェクトへのポインター、またはそのような基本クラスを表すサブオブジェクト (1.8) へのポインターでなければなりません。オブジェクト(箇条10)。そうでない場合、動作は未定義です。2 番目の選択肢 (delete array) では、delete のオペランドの値は、前の配列 new-expression から得られたポインタ値になります。77) そうでない場合、動作は未定義です。[注: これは、削除式の構文が、new 式の構文ではなく、new によって割り当てられたオブジェクトの型と一致する必要があることを意味します。—終わりのメモ][ 注: const 型へのポインターは、削除式のオペランドにすることができます。削除式のオペランドとして使用する前に、ポインター式の定数 (5.2.11) をキャストする必要はありません。—終わりのメモ]
これは、ポイントされているメモリとポイントしているポインタが両方ともPODである場合に問題なく機能します。この場合、とにかくデストラクタは呼び出されず、メモリアロケータはメモリ内に格納されているタイプを認識または認識しません。
これが非PODタイプで問題ない唯一のケースは、ポインターがポインターのサブタイプであり(たとえば、車両で車を指している*)、ポインターのデストラクタが仮想であると宣言されている場合です。
malloc/freeを使用するようにコードを変更しました。MSVCがプレーンな古いデータのnew/deleteを実装する方法を知っていますが(この場合のSOME_STRUCTはWin32構造体であるため、単純なCです)、それが移植可能な手法であるかどうかを知りたかっただけです。
そうではないので、そういうものを使います。
これは機能するはずですが、SOME_STRUCTはchar *ではないため(単なるtypedefでない限り)、安全であるとは保証できないと思います。
さらに、さまざまなタイプの参照を使用しているため、* pアクセスを引き続き使用し、メモリが削除されている場合、ランタイムエラーが発生します。
これは安全ではありません。これまでのところ、これを行うことの狂気を十分に強調した回答はありませんでした。自分が本物のプログラマーだと思っている場合や、チームでプロのプログラマーとして働きたいと考えている場合は、絶対にやらないでください。現時点では、構造体に非デストラクタが含まれているとしか言えませんが、将来のために厄介な可能性のあるコンパイラとシステム固有のトラップを敷設しています。また、コードが期待どおりに機能しない可能性もあります。期待できる最善のことは、クラッシュしないことです。ただし、 new を介した配列の割り当てでは、返されるポインターの前のバイトに余分なメモリが割り当てられることが多いため、ゆっくりとメモリ リークが発生すると思われます。自分だと思っている記憶を解放することはできません。適切なメモリ割り当てルーチンは、Lint などのツールと同様に、この不一致を検出する必要があります。
そんなことは絶対にやめて、そのようなばかげたことを考えるようになった思考過程が何であれ、頭から追い出してください。
new/delete の代わりに malloc/free を使用すると、malloc と free はタイプを気にしません。
したがって、C ライクな POD (組み込み型や構造体などの単純な古いデータ) を使用している場合は、ある型を malloc し、別の型を解放することができます。これは動作してもスタイルが悪いことに注意してください。