C++ のヘッダファイルを #include するだけで使える GC 書いてみた

そういえば C++ のヘッダファイルを #include するだけで使える GC を書きました。使い方は下のサンプルコードを見てもらえばいいとして、特徴としては、

  • ヘッダファイルを #include するだけで使える
  • C++ の標準機能だけを使っているのでポータブル*1
  • mark-and-sweep, precise GC

ってなあたりでしょうか。コードは GitHub - kazuho/picogc: a tiny, portable, precise, mark-and-sweep GC in C++ にあります。

C++ のプロジェクトで、ちょっとここだけは GC がほしいんだけど、ってなケースで使いやすいと思います。速度も、そこそこでるんじゃないかな*2

というわけで、以下、サンプルコード。軽く説明しておくと、

  • GC を使うクラスは picogc::gc_object を継承する
    • メンバ変数に GC 対象のオブジェクトがある場合は gc_mark 関数を実装する
  • GC オブジェクトを扱う関数では picogc::scope を作ってガード
    • ローカル変数は picogc::local に代入

みたいな感じ。

#include "picogc.h"

class LinkedList : public picogc::gc_object {
  std::string str_;
  LinkedList* next_;
public:
  LinkedList(const std::string& str, LinkedList* next)
    : str_(str), next_(next)
  {}
  const std::string& str() const { return str_; }
  LinkedList* next() { return next_; }
  virtual void gc_mark(picogc::gc* gc) {
    gc->mark(next_);
  }
};

static picogc::local<LinkedList> buildArgsList(int argc, char** argv)
{
  picogc::scope scope;

  picogc::local<LinkedList> args = NULL;
  for (int i = argc - 1; argc > 0; i--)
    args = new LinkedList(argv[i], args);

  return scope.close(args);
}

int main(int argc, char** argv)
{
  picogc::gc gc;
  picogc::gc_scope gc_scope(&gc);
  picogc::scope scope;

  // create a linked list of arguments
  picogc::local<LinkedList> args = buildArgsList(argc, argv);

  // print the list
  for (picogc::local<LinkedList> arg = args; arg != NULL; arg = arg->next())
    std::cout << arg->str() << std::endl;

  return 0;
}

それでは have fun!

*1:operator new の返り値が 4-byte にアラインされるという要請を除きます

*2:gc_object のコンストラクタ引数とか gc_atomic_object とかを使ってチューニングしてください