わかりましたので、正確な「マークとスイープ」ガベージ コレクターを C++ で書きたいと思っています。すべてのポインターが「RelocObject」にラップされ、ヒープ用に単一のメモリブロックがあるため、役立つ決定を下したことを願っています。これは次のようになります。
// This class acts as an indirection to the actual object in memory so that it can be
// relocated in the sweep phase of garbage collector
class MemBlock
{
public:
void* Get( void ) { return m_ptr; }
private:
MemBlock( void ) : m_ptr( NULL ){}
void* m_ptr;
};
// This is of the same size as the above class and is directly cast to it, but is
// typed so that we can easily debug the underlying object
template<typename _Type_>
class TypedBlock
{
public:
_Type_* Get( void ) { return m_pObject; }
private:
TypedBlock( void ) : m_pObject( NULL ){}
// Pointer to actual object in memory
_Type_* m_pObject;
};
// This is our wrapper class that every pointer is wrapped in
template< typename _Type_ >
class RelocObject
{
public:
RelocObject( void ) : m_pRef( NULL ) {}
static RelocObject New( void )
{
RelocObject ref( (TypedBlock<_Type_>*)Allocator()->Alloc( this, sizeof(_Type_), __alignof(_Type_) ) );
new ( ref.m_pRef->Get() ) _Type_();
return ref;
}
~RelocObject(){}
_Type_* operator-> ( void ) const
{
assert( m_pRef && "ERROR! Object is null\n" );
return (_Type_*)m_pRef->Get();
}
// Equality
bool operator ==(const RelocObject& rhs) const { return m_pRef->Get() == rhs.m_pRef->Get(); }
bool operator !=(const RelocObject& rhs) const { return m_pRef->Get() != rhs.m_pRef->Get(); }
RelocObject& operator= ( const RelocObject& rhs )
{
if(this == &rhs) return *this;
m_pRef = rhs.m_pRef;
return *this;
}
private:
RelocObject( TypedBlock<_Type_>* pRef ) : m_pRef( pRef )
{
assert( m_pRef && "ERROR! Can't construct a null object\n");
}
RelocObject* operator& ( void ) { return this; }
_Type_& operator* ( void ) const { return *(_Type_*)m_pRef->Get(); }
// SS:
TypedBlock<_Type_>* m_pRef;
};
// We would use it like so...
typedef RelocObject<Impl::Foo> Foo;
void main( void )
{
Foo foo = Foo::New();
}
したがって、「RelocObject::New」で割り当てるときに「ルート」RelocObjects を見つけるために、RelocObject の「this」ポインターをアロケーター (ガベージ コレクター) に渡します。次に、アロケータは、「this」ポインタがヒープのメモリ ブロックの範囲内にあるかどうかを確認します。範囲内にある場合は、ルートではないと見なすことができます。
そのため、各子オブジェクト内にある 0 個以上の RelocObjects を使用して、ルートから子オブジェクトまでトレースしたい場合に問題が発生します。
「正確な」メソッドを使用して、クラス (つまり、子オブジェクト) 内の RelocObjects を見つけたいと考えています。リフレクション アプローチを使用して、各クラスの RelocObjects がある場所にユーザーを登録させることができます。ただし、これは非常にエラーが発生しやすいため、これを自動的に行いたいと考えています。
その代わりに、Clang を使用してコンパイル時にクラス内の RelocObjects のオフセットを見つけ、プログラムの開始時にこの情報をロードし、これをガベージ コレクターのマーク フェーズで使用してトレースし、子オブジェクトをマークすることを検討しています。
私の質問は、Clang が役に立ちますか? コンパイル時のフックを使用して、コンパイル中にあらゆる種類の型情報を収集できると聞きました。もしそうなら、私はClangで何を探すべきですか?つまり、この種のことを行う例はありますか?
明確にするために、Clangを使用して、ユーザーが「ヒント」を提供することなく、FooBで「Foo」(RelocObjectのtypedef)のオフセットを自動的に見つけたい、つまり、次のように記述します。
class FooB
{
public:
int m_a;
Foo m_ptr;
};
助けてくれてありがとう。