本当は怖いHPC

HPC屋の趣味&実益ブログ

placement new

言語処理系のGC

Lispインタプリタを書いていて、stop and copyのGCを書くためにplacement newを勉強してました。
でも、試行錯誤してるうちに気づいたら使ってなかった…orz。

せっかくなので、placement newについてまとめ。
詳しくはEffective C++ 第3版を参照。

Effective C++ 原著第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)

Effective C++ 原著第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)

placement new の説明

まず、基本的なところからいくと、C++においてはメモリ確保と初期化は別物。前者がoperator new、後者がコンストラクタです。

operator new サイズ(std::size_t型)を受け取り、メモリ領域を返す
コンストラクタ 確保されたメモリ領域にオブジェクトを構築する

そして、operator newオーバーロードするといろいろなトリックが使えるようになるのですが、これを可能にするのがplacement newと呼ばれるテクニック((placement newの定義は多少あいまいで、単純にoperator newオーバーロードする場合もあれば、サイズ以外の情報を取るoperator newのことを指す場合もある))です。特に、operator newにメモリ領域を渡して、それをそのままオブジェクトに渡すというパターンがもっとも良く使われます。これによって、任意のメモリ領域にオブジェクトを構築することができます。

この、一番良く使う「あらかじめ用意したメモリ領域にオブジェクトを構築する」パターンの例。よく使うだけあって(たぶん)、すでに標準で用意されています。

// test.cpp
#include<iostream>
#include<new>

using namespace std;

// 整数加算を蓄積するクラス
class Acc {
  int _val;
public:
  // コンストラクタとデストラクタ
  Acc(int val=0) : _val(val) {}
  ~Acc() { }

  int call(int v=0) {
    _val += v;
    return _val;
  }
};

int main() {
  // Accクラスのサイズ分のメモリを確保し、そこにAccオブジェクトを構築する
  char *p = new char[sizeof(Acc)];

  // <new>ヘッダであらかじめ用意されているplacement new。
  Acc *a = new(p) Acc;

  cout << a->call(3) << endl;
  cout << a->call(7) << endl;

  // オブジェクトの破壊とメモリの開放は今や別処理。
  a->~Acc();
  delete[] p;

  return 0;
}

実行結果。

$ g++ test.cpp && ./a.out                                                                                              
3
10
【広告】