読者です 読者をやめる 読者になる 読者になる

newした位置が解るnew

が欲しい。
といつも思っているんだけれど、
なかなかそうはいかないのよね、というお話。

デバッグ用のメモリ確保ルーチンなどには、
そのメモリブロックが何の用途で使われているのかヘッダに記憶しておいたりする。
要するに、

new (__LINE__, __FILE__) Hoge();

みたいにnewの引数にそれと解るものを書いておく。そして、それをメモリの頭に隠しておく。するとメモリの把握に大変便利。
ただ、こんな書き方をみんなしたい訳じゃない。
めんどくさい。めんどくさい。かっこ悪い。だいたい、デバッグ時だけでいいんだ。わかるのわ。
じゃ、

#define new new (__LINE__, __FILE__)

こんなことをしたら、これは、

Hoge* hoge = new (buffer) Hoge();

なんてことをしたときに、

Hoge* hoge = new (666,"Hoge.cpp")(buffer) Hoge();

なんて展開されて寂しいことになる。

うーん、
じゃ、こうだ。

#define new MemObject(__LINE__, __FILE__) * new

これで、

Hoge* hoge = new Hoge();

は、

Hoge* hoge = MemObject(666,"Hoge.cpp") * new Hoge();

に展開される。なので、newの後に()がついていて引数があってもへっちゃらだ。
勿論、

class MemObject
{
public:
    MemObject(int line, const char* filename)
    : line_(line)
    , filename_(filename)
    {
    }
    int line_;
    const char* filename_;
};

として、

template <class T> inline T* operator*(const MemObject& object, T* p)
{
    // ここでobjectの情報を確保済みメモリブロックに埋め込む
    cout << object.filename_ << ":" << object.line_ << endl;    // 例えば出力してみる
    return p;
}

なんてことはしないといけない。
さて、これで、心おきなくnewと書けるようになった……、
どこでnewしたかも勝手に記憶されるようになった……、
万事解決、
……というわけではなく、
このマジックを使うためには全てのhやcppに対し暗黙的にインクルードされるような仕組みが有ることが望ましいが、
そうしたマジックが影響を及ぼすところで
operator newを書こうとすると#undef newしなければならない
というオチが待ってる。
VCなんかはマクロを#push_macroできたりするのだが、
そうはいかないコンパイラもあるわけで。

うんがうぐ。
これを綺麗にできる仕組みはないものかなあ。