Skip to content

Instantly share code, notes, and snippets.

@nbdd0121
Created January 24, 2015 06:18
Show Gist options
  • Save nbdd0121/b37457d9c27ec82c592a to your computer and use it in GitHub Desktop.
Save nbdd0121/b37457d9c27ec82c592a to your computer and use it in GitHub Desktop.
Simple mark-and-sweep GC (coded as a beginner of C++)
#include <iostream>
#include <vector>
#define debug(statement) statement
// #define debug(statement)
// Above one for release use
/* Declarations */
class GCObject;
class GCPool;
class GCPool {
public:
void gc();
private:
std::vector<GCObject*> objs;
friend GCObject;
};
class GCObject{
public:
GCObject(GCPool& p);
virtual void markReference();
virtual ~GCObject();
protected:
bool gcVisited = false;
int refCount = 0;
friend GCPool;
template <class Type> friend class GCHandle;
};
/* Implementations */
void GCPool::gc(){
debug(std::cout << "GC start" << std::endl);
for(auto a:objs){
if(a->refCount)
a->markReference();
}
for(auto a = objs.begin(); a<objs.end();){
if(!(*a)->gcVisited){
auto obj = *a;
objs.erase(a);
delete obj;
}else{
(*a)->gcVisited = false;
a++;
}
}
debug(std::cout << "GC end" << std::endl);
}
GCObject::GCObject(GCPool& p){
p.objs.push_back(this);
}
void GCObject::markReference(){
if(gcVisited)
return;
gcVisited=true;
}
GCObject::~GCObject(){}
template <class Type>
class GCHandle {
public:
inline GCHandle(Type& t):ptr(t){
t.refCount++;
};
inline GCHandle(Type* t):GCHandle(*t){};
inline operator Type*(){
return &ptr;
}
inline operator Type&(){
return ptr;
}
inline Type& operator *(){
return ptr;
}
inline Type* operator ->(){
return &ptr;
}
inline ~GCHandle(){
ptr.refCount--;
}
private:
Type& ptr;
};
/* Examples */
class GCString:public GCObject{
public:
GCString(const char* str, GCPool& pool):GCObject(pool), content(str){
debug(std::cout << "Construct GCString " << content << std::endl);
}
virtual ~GCString(){
debug(std::cout << "Destruct GCString " << content << std::endl);
}
const char* content;
};
class GCArray:public GCObject{
public:
GCArray(GCPool& pool):GCObject(pool) {
debug(std::cout << "Construct GCArray " << std::endl);
}
void add(GCObject& obj){
objs.push_back(&obj);
}
virtual void markReference(){
if(gcVisited)
return;
else
gcVisited=true;
for(auto o:objs){
o->markReference();
}
}
virtual ~GCArray(){
debug(std::cout << "Destruct GCArray " << std::endl);
}
private:
std::vector<GCObject*> objs;
};
GCPool pool;
int main(void){
GCHandle<GCArray> array(new GCArray(pool));
GCHandle<GCString> a(new GCString("A", pool));
{
GCHandle<GCString> b(new GCString("B", pool));
array->add(b);
GCHandle<GCString> c(new GCString("C",pool));
std::cout << "Test: " << c->content << std::endl; // Easy to use
pool.gc(); // Nothing get freed, since GCHandle maintains ownership
}
pool.gc();
// c get freed, since no reference to C
// b is not, since array points to b
// array and a is not freed because GCHandle's ownership made them root
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment