new
ライブラリ (メイン アプリとは異なるビルド) でキーワードを使用する場合、メイン アプリでキーワードを削除するとdelete
、クラッシュ/エラーが発生する可能性はありますか?
6 に答える
場合によります。静的ライブラリについて話している場合は、おそらく問題ありません。コードは、同じ C++ ランタイム ライブラリを使用して、メイン プログラムと同じコンテキストで実行されます。これは、new
とdelete
が同じヒープを使用することを意味します。
共有ライブラリ (DLL) について話している場合は、おそらく問題ありません。DLL で実行されているコードは、別の C++ ランタイム ライブラリを使用している可能性があります。つまり、ヒープのレイアウトが異なります。DLL がまったく別のヒープを使用している可能性があります。
DLL によって割り当てられたポインターを (メイン プログラムで)呼び出すdelete
(またはその逆) と、(せいぜい) すぐにクラッシュするか、(最悪の場合) 追跡に時間がかかるメモリ破損が発生します。
いくつかのオプションがあります。1 つ目は、「ファクトリ メソッド」パターンを使用して、これらのオブジェクトを作成および削除することです。
Foo *CreateFoo();
void DeleteFoo(Foo *p);
これらはヘッダー ファイルに実装しないでください。
Destroy
または、オブジェクトにメソッドを定義できます。
class Foo
{
~Foo();
public:
virtual void Destroy();
};
...繰り返しますが、これをヘッダー ファイルに実装しないでください。次のように実装します。
void Foo::Destroy()
{
delete this;
// don't do anything that accesses this object past this point.
}
Foo のデストラクタはプライベートであるため、 を呼び出す必要があることに注意してくださいFoo::Destroy
。
Microsoft COM も同様のことをRelease
行い、参照カウントがゼロになったときにオブジェクトを削除するメソッドを定義します。
はい、そうです。特に、デバッグ/リリース ヒープが異なる場合に問題が発生します。また、ライブラリが新しい配置またはカスタム ヒープを使用している場合にも、問題が発生します。ただし、デバッグ/リリースの問題は最も一般的です。
はい、そうします。簡単な解決策は、メイン アプリケーションから呼び出すことができる Create および Delete 関数をライブラリに提供することです。Create 関数は new を実行してポインターを返します。ポインターは後で削除のために Delete 関数に渡されます。
これは、私が Windows でのみ見た問題です。
Unix システムでは、共有ライブラリを同じプログラム内の同じライブラリの異なるバージョンにリンクすることを強制する習慣はなく、ロードされたすべてのシンボルはグローバルに表示されます。つまり、オブジェクトがコードのある部分で割り当てられ、別の部分で削除された場合、両方が同じシステム ライブラリを使用してそれを実行します。
Windows がさまざまな C ランタイム DLL を使用して作成するこの問題は、C プログラマーにとって本当に厄介で不自然です。C ライブラリを見てください。文字列を malloc し、プログラマが free() を呼び出すことを期待する strdup のような関数があります。ただし、Windows の独自のライブラリで同じことを行い、爆発を待ちます。開発中には発生せず、コンパイル済みの DLL を他の貧弱な sap に渡した後にのみ発生するため、待つ必要があります。
そこに問題があることはまったく正しいですが、ほとんどの場合、他の回答 (これまで) が提案したものよりもさらに簡単な解決策があります。new と delete を自由に使用し続けることができます。DLL の境界を越えて使用される可能性のあるライブラリ内の各クラスに対して new と delete をオーバーロードするだけです。
個人的には、必要な機能を提供するために単純なクラスを定義しました。
class NewDelete
{
public:
void *operator new (size_t size);
void operator delete (void *memory);
void *operator new (size_t size, void *ptr);
void operator delete (void *memory, void *ptr);
};
これらの 4 つのメンバー関数がすべて同じ DLL で定義されている限り、このクラスから派生するクラスは自動的に「DLL セーフ」になります。new と delete は、DLL の境界を気にせずに通常どおり使用できます。