Tuesday, February 17, 2015

C++11 Weak Pointers


C++11 introduces std::shared_ptr and std::weak_ptr to manage shared memory with reference counting and weak references. Weak references are used by children in a tree structure to reference their parent, and break the reference cycle. Methods of the child class need to take extra care with the parent pointer (the weak pointer), to promote it to a shared pointer, and only use it if the pointer is still alive.

Rusthon detects when you have a reference cycle between two classes and automatically uses weak references to break the cycle. The parent class must contain a list of child objects, then when the parent is set on the child it becomes a weak pointer. For more info, check out the wiki page.

rusthon input

The line below par = self.parent promotes the weak pointer to a reference counted shared pointer that could also be null if the parent has been deleted, so you need to check if it is None before it can be used. The last line c1.bar() will crash with a segmentation fault because it is used after the parent has been deleted, and the bar function is not checking if self.parent is not None.

class Parent:
 def __init__(self, children:[]Child ):
  self.children = children

class Child:
 def __init__(self, parent:Parent ):
  self.parent = parent

 def foo(self) ->int:
  par = self.parent
  if par is not None:
   return 1
  else:
   print('parent is gone..')

 def bar(self):
  print self.parent.children

def make_child(p:Parent) -> Child:
 c = Child(p)
 p.children.push_back(c)
 return c


def main():
 children = []Child()
 p = Parent( children )
 c1 = make_child(p)
 c2 = make_child(p)
 print c1.foo()
 c1.bar()
 del p
 print c1.foo()
 #uncomment to segfault##c1.bar()

c++11 output

class Parent {
  public:
 std::string __class__;
 std::shared_ptr<std::vector< std::shared_ptr<Child> >>  children;
 void __init__(std::shared_ptr<std::vector<std::shared_ptr<Child>>> children);
 Parent() {__class__ = std::string("Parent");}
 std::string getclassname() {return this->__class__;}
};
class Child {
  public:
 std::string __class__;
 std::weak_ptr<Parent>  parent;
 void __init__(std::shared_ptr<Parent> parent);
 int foo();
 void bar();
 Child() {__class__ = std::string("Child");}
 std::string getclassname() {return this->__class__;}
};

 void Parent::__init__(std::shared_ptr<std::vector<std::shared_ptr<Child>>> children) {
  this->children = children;
 }

 void Child::__init__(std::shared_ptr<Parent> parent) {
  this->parent = parent;
 }


 int Child::foo() {
  auto par = this->parent.lock();
  if (( par ) != nullptr) {
   return 1;
  } else {
   std::cout << std::string("parent is gone..") << std::endl;
  }
 }

 void Child::bar() {
  std::cout << this->parent.lock()->children << std::endl;
 }

std::shared_ptr<Child> make_child(std::shared_ptr<Parent> p) {
 Child  _ref_c = Child{};_ref_c.__init__(p);
 std::shared_ptr<Child> c = std::make_shared<Child>(_ref_c);
 p->children->push_back(c);
 return c;
}

int main() {

 std::vector<std::shared_ptr<Child>> _ref_children = {};
 std::shared_ptr<std::vector<std::shared_ptr<Child>>> children = std::make_shared<std::vector<std::shared_ptr<Child>>>(_ref_children);
 Parent  _ref_p = Parent{};_ref_p.__init__(children);
 std::shared_ptr<Parent> p = std::make_shared<Parent>(_ref_p);
 auto c1 = make_child(p);
 auto c2 = make_child(p);
 std::cout << c1->foo() << std::endl;
 c1->bar();
 p.reset();
 std::cout << c1->foo() << std::endl;
 return 0;
}

No comments:

Post a Comment