VC6 Tips / C++での独自のnew deleteの作り方テクニック

C++でnew deleteを自作する時に既存のnew deleteと共存させたい事がある。
その時の解決方法としていくつか方法がある。

  1. クラス毎にnew deleteを書く
  2. 新たにnamespaceを作ってそこに新しいnew deleteを宣言
  3. 独自の引数を加えたnew deleteを宣言
1. は面倒すぎるので論外として・・・
2. は私も最初試した事があるがいちいちnew deleteの為に新しいネームスペースにoperatorを書くのは面倒 ソースコード的にスマートではない。new deleteとして定義させる意味が無い。そしてnamespace外から使用しようとするとコンパイラから怒られる事がある。

ということで今回は3.を紹介する。

独自の構造体を用意してそれをnew deleteの引数にするといった方法だ。
この方法を発見した当時は浮かれていた。(伏線)
続きを読む


#include <iostream>
using namespace std;

struct allocator_signature{
//このtはあくまでメンバのない構造体は認めないコンパイラ用の保険である。
 int t;
};

void *operator new(std::size_t size,allocator_signature sig){
  return malloc(size);
}
void operator delete(void *p,allocator_signature sig){
  if(p)  
    free(p);
}

///グローバルに定義しないとコンパイラは認めてくれない
allocator_signature gt;
///ここのMALLOC_NEWをnewに置き換えるとnewをオーバーライドできる。
///注意としてはnewが定義された後にこのマクロを宣言して
///その後にソースコードを宣言する事である。
#define MALLOC_NEW new(gt)
///delete p のようなかたちに出来なくなってしまうが共存させるためには仕方ない・・・
#define MALLOC_DELETE(Type,ptr) \
  ptr->~Type();  \
  operator delete(ptr,gt)


struct Test{
  Test(){
    cout << "construct" << endl;
  }
  ~Test(){
    cout << "destruct" << endl;
  }
};

int main(int argc,const char **argv)
{
  Test *t = new Test;

  delete t;

  t = MALLOC_NEW Test;
  MALLOC_DELETE( Test,t );

  return 0;
}

さぁ、見て欲しい。独自のdeleteを既存のdeleteと共存させて使用するには以上のような面倒な記述をしなくてはいけないのだ。浮かれていたのがバカみたいだった。思いついた当時は大発見と思っていたのにもかかわらず・・・(人間が作ったものから大発見と言うのは大それた事だとも感じてしまうが・・・)
これでは本末転倒である。
原理解説(http://www.fides.dti.ne.jp/~oka-t/cpplab-placement-new-2.html
と言う事で、実はSTLにはこれを克服するためのテンプレートの仕様がある。
下の見出しを見て欲しい。