Skip to content

Implementation of Deterministic Garbage Collector Pointer

License

Notifications You must be signed in to change notification settings

redradist/cpp_gc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Intruduction

Consider the following example:

#include <iostream>
#include <memory>

class Child;

class Parent {
 public:
  Parent() {
    std::cout << "Parent()" << std::endl;
  }

  ~Parent() {
    std::cout << "~Parent()" << std::endl;
  }

  void createChild() {
    child_ptr_ = std::make_shared<Child>();
  }

  std::shared_ptr<Child> getChild() {
    return child_ptr_;
  }

 private:
  std::shared_ptr<Child> child_ptr_;
};

class Child {
 public:
  Child() {
    std::cout << "Child()" << std::endl;
  }

  ~Child() {
    std::cout << "~Child()" << std::endl;
  }

  void setParent(std::shared_ptr<Parent> parentPtr) {
    parent_ptr_ = parentPtr;
  }

 private:
  std::shared_ptr<Parent> parent_ptr_;
};

int main() {
  auto parent = std::make_shared<Parent>();
  parent->createChild();
  parent->getChild()->setParent(parent);
  return 0;
}

In this example you will get memory leak due to cyclic dependecy ... :(

To fix it you should be very careful and use in Child class instead of std::shared_ptr -> std::weak_ptr as in example below:

...

class Child {

  ...

  void setParent(std::shared_ptr<Parent> parentPtr) {
    parent_ptr_ = parentPtr;
  }

 private:
  std::weak_ptr<Parent> parent_ptr_;
};

...

But what if we can combine determinism of std::shared_ptr and garbadge collector ??

memory::gc_ptr is exactly for this purpose !! Consider the follwoing example:

#include <iostream>
#include "gc_ptr.hpp"

class Child;

class Parent {
 public:
  Parent() {
    std::cout << "Parent()" << std::endl;
  }

  ~Parent() {
    std::cout << "~Parent()" << std::endl;
  }

  void createChild() {
    child_ptr_.create_object();
  }

  memory::gc_ptr<Child> getChild() {
    return child_ptr_;
  }

 private:
  memory::gc_ptr<Child> child_ptr_;
};

class Child {
 public:
  Child() {
    std::cout << "Child()" << std::endl;
  }

  ~Child() {
    std::cout << "~Child()" << std::endl;
  }

  void setParent(memory::gc_ptr<Parent> parentPtr) {
    parent_ptr_ = parentPtr;
  }

 private:
  memory::gc_ptr<Parent> parent_ptr_;
};

int main() {
  memory::gc_ptr<Parent> parent;
  parent.create_object();
  parent->createChild();
  parent->getChild()->setParent(parent);
  return 0;
}

This code is easier that you should not track possible cyclic dependecies by eyes and still you will get deterministic behaviour

Advantages

This feature conforms with zero-overhead principle !! You do not pay if you do not use it and pay if you use it ...

Known issues

For simplicity my code generation tool does not conforms with this principle, but optimizer will eliminate all unused code that was generated Also simplicity gc_ptr could be passed only in lambda expression that is used for std::thread construction It also currently does not work with STL, but it will soon ...

How to use it

On Ubuntu:

sudo apt-get install libclang
sudo python3 -m pip install clang

Then in your cmake based project add the following line before project directive:

...
set(CMAKE_CXX_COMPILER <path_to_clang_extras.py>)
project(<project_name>)
...

For more information how to use take a look at example folder
Enjoy ;)

About

Implementation of Deterministic Garbage Collector Pointer

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published