2009-12-03

placement newでBoehm GCのgc_cleanup

Boehm GCに付属のgc_cpp.hでは、gc_cleanupという構造体が提供されている。これは継承するとGC時に自動的にデストラクタを呼んでくれるというもので、非推奨のGC_finalize_allと組み合わせて使うとリソース管理に非常に便利だ。(つまり、終了時に他ライブラリのリソースを開放させることができる)
gc_cleanupを継承するように書き換えることができればいいが、それも面倒な場合がある。
一度スマートポインタ的なものを試した。
#ifndef GC_PTR_HPP_
#define GC_PTR_HPP_
class gc_cleanup;
template <typename T>
class gc_ptr : public gc_cleanup
{
T *ptr;
const P<T> &operator =(T *);
public:
P(T *t) : ptr(t) {}
operator T *() { return ptr; }
T *operator ->() { return ptr; }
~P() { delete ptr; }
};
#endif
view raw gc_ptr.hpp hosted with ❤ by GitHub

逆に不便になった。(というか、スマートポインタを使いたくないからBoehm GCを使っている)
placement newというものを使うとコンストラクタのメモリ確保をフックできるようなので、それで試してみた。
たとえば new (gc_cleanup_alloc<std::vector<int > >()) std::vector<int>() のように使う。
#ifndef GC_CLEANUP_ALLOC_H_
#define GC_CLEANUP_ALLOC_H_
#ifdef __cplusplus
#include <new>
// C++用。allocで使う。
template <typename T>
static void gc_cleanup_alloc_func(void *pself, void *)
{
GC_REGISTER_FINALIZER_NO_ORDER(t, NULL, NULL, NULL, NULL);
static_cast<T *>(pself)->~T();
}
template <typename T>
class GCCleanupAllocTag {};
// usage: T *t = new (gc_cleanup_alloc<T>()) T();
template <typename T>
inline AllocTag<T> gc_cleanup_alloc()
{
return GCCleanupAllocTag<T>();
}
// std::bad_allocを投げる。
template <typename T>
inline void *operator new(std::size_t size, const AllocTag<T> &)
{
void *t = GC_MALLOC(size);
if (t == NULL) { throw std::bad_alloc(); }
GC_REGISTER_FINALIZER_NO_ORDER(t, gc_cleanup_alloc_func<T>, NULL, NULL, NULL);
return t;
}
// see http://parashift.com/c++-faq-lite/dtors.html [11.14]
template <typename T>
inline void operator delete(void *t, const AllocTag<T> &)
{
GC_REGISTER_FINALIZER_NO_ORDER(t, NULL, NULL, NULL, NULL);
GC_FREE(t);
}
#endif /* defined(__cplusplus) */
#endif /* !defined(GC_CLEANUP_ALLOC_H_) */
いまのところ問題なく動いている。

0 件のコメント:

コメントを投稿