ProgrammingC++開発者、システムプログラマ

C++におけるoperator new/operator deleteのメカニズムについて説明してください。new/deleteとどのように異なり、いつ、なぜ演算子関数がユーザー定義クラスでオーバーライドされるのですか?

Hintsage AIアシスタントで面接を突破

答え。

C++におけるoperator newおよびoperator deleteは、オブジェクトをnewおよびdelete演算子を使用して配置および削除する際に呼び出されるメモリの割り当ておよび解放関数です。デフォルトでは標準アロケータを使用しますが、クラス内ではメモリ割り当てを細かく制御するためにオーバーロードできます。

  • operator newは、コンストラクタを呼ばずに「生」のメモリ領域を割り当てます。
  • メモリが割り当てられた後、自動的にオブジェクトのコンストラクタが呼ばれます。
  • operator deleteは、オブジェクトのデストラクタが完了した後にメモリを解放します。

使用法(グローバルおよびローカルバージョン):

  • グローバルバージョンはデフォルトで適用されます(例えば、new intの場合など)。
  • クラス内で特定のoperator newをオーバーライドすることで、そのクラスのオブジェクトに対してメモリの使用を最適化できます(例えば、オブジェクトプール、トレース、ブロックの再利用など)。

operator new/operator deleteのオーバーロードの例:

#include <iostream> class TrackAlloc { public: void* operator new(size_t size) { std::cout << "TrackAlloc::new for " << size << " bytes "; return ::operator new(size); } void operator delete(void* ptr) { std::cout << "TrackAlloc::delete "; ::operator delete(ptr); } };

注意点:

  • 引数付きの新しいオブジェクトの呼び出し(プレースメントnew)は、別のオーバーロードが必要です。
  • オーバーロードされた演算子は、クラスのオブジェクトの作成/削除時にのみ呼び出され、新しい配列や削除配列には呼び出されません。それらには個別のoperator new[]/delete[]をオーバーロードすることができます。
  • メモリ操作は危険です — 例外処理を正しく行う必要があります。

試験のしっぽ。

"クラス内でオペレーターnewをオーバーライドし、その後、派生クラスの変数を介してオブジェクトを作成した場合、どのバージョンのoperator newが呼び出されますか?"

答え: オブジェクトが作成されるクラスのoperator newが呼び出されます。もし派生クラスにoperator newが実装されていない場合、基底クラスまたはグローバルバージョンの適切なバージョンを探す試みが行われます。

例:

struct Base { void* operator new(size_t s) { std::cout << "Base new "; return ::operator new(s); } }; struct Derived : Base {}; Derived* p = new Derived; // Base::operator newが呼び出されます!

このトピックの細かな点を知らなかったために実際に発生したエラーの例。


物語

開発者は例外処理の正しいサポートなしにoperator new/deleteをオーバーロードしました。コンストラクタ内で例外がスローされた場合、メモリが解放されず、リークが発生しました。


物語

operator new[]およびoperator delete[]を不適切に実装しました:配列を保持するクラスでは、新しい実装が呼び出されず、デフォルトのバージョンが使用されることで、メモリの割り当てと解放のロジックが同期されなくなりました。


物語

グローバルoperator newのオーバーライドはサードパーティライブラリの機能に影響を与えました:すべてのオブジェクト(一時オブジェクトおよびSTLのオブジェクトを含む)がログを記録するアロケータを介して割り当てられ、アプリケーションコアのパフォーマンスが著しく低下しました。