LoginSignup
0
0

More than 5 years have passed since last update.

new/delete演算子の対応付け

Posted at

通常のnew/delete(an usual (de)allocation function)には以下の書き方があります。

void* operator new(std::size_t);
void operator delete(void*);
void operator delete(void*, std::size_t);

deleteには二通りの書き方がされていますが、両方書かれた場合は上のものが優先されます。

配置new/delete(a placement (de)allocation function)は上の物に引数を足したものを総称して言うものです。

void* operator new(std::size_t, ...); // 第二引数以降は何でもいいけど、1つ以上は必要
void operator delete(void*, ...); // 同上

配置deleteは聞き慣れないかもしれないので、ここで説明しておきます。
通常、newを呼び出して領域の確保に成功したもののコンストラクタで例外が発生した場合、自動でdeleteが呼び出され、領域が解放されます。(デストラクタは呼ばれません。)これは、配置newでも同じで、配置newの場合は同じシグニチャの配置deleteを呼ぼうとするのです。
従って、対応するdeleteがなければ、deleteが呼ばれず、解放処理が行われません。(配置newでは領域を確保するとは限りませんが、明示的に空のdeleteを用意することが望ましいです。)

struct something
{
  something() {}

  static void* operator new(std::size_t n, void* place)
  {
    return ::operator new(n, place);
  }
  static void operator delete(void*, void*);
};

このようなクラスを書き、newするとdeleteが定義されていないと怒られます。コンパイラの作るnew構文内の例外ハンドラでdeleteが参照されている証拠ですね。ちなみに、コンストラクタをnoexceptに指定すると最適化で例外ハンドラが消滅し、deleteが参照されなくなってコンパイルが通ったりするかもしれません。

ここで、void* operator new(std::size_t, std::size_t);を定義し、さらにvoid operator delete(void*);がなく、void operator delete(void*, std::size_t);のみが定義される場合、deleteが通常とも配置とも受け取れるためにill-formatとなります。

参考

結構誤字がひどい。
これだけ読めば全部がわかるC++のoperator new/deleteオーバーロードの注意点

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0