Memory Management Conventions

Memory management conventions depend on the type of the object being managed. However, there are only a few possible memory management schemes that are used consistently throughout the Inti libraries.

Standard C++ Defaults

This is the memory management you would expect for a built-in C++ type. The rules include:

Strict Reference Counting

Strict reference counting is very painful to use, so it's generally avoided in Inti. However it's simpler to explain than the reference counting Inti uses most often (see the section called Reference counting with a "floating" reference).

The strict_ptr<T> smart pointer class is intended for use with these objects. strict_ptr<T> increments the reference count on the object it points to. Note that the following code is dangerous:
  strict_ptr<Button> button = new Button;
The button starts with a reference count of 1, and strict_ptr<Button> will increment it. So the button's reference count is now 2. An eventual call to unref() is required.

Strictly refcounted objects follow certain rules:

Reference counting with a "floating" reference

This is the memory management scheme used by most nontrivial objects in Inti, including all widgets. It's identical to strict reference counting (see the section called Strict Reference Counting), with a twist: the object can have a "floating" reference count, which is not owned. Any code section can "sink" the floating reference count; once sunk, the object effectively has strict reference counting. There is no way to "unsink" an object.

The purpose of the floating reference is to keep the object alive until it finds its first owner. An owner can "adopt" an object by adding a reference count, and removing the floating reference. Consider the following code:
  Window * win = new Window;
  win->add (new Button ("My Button"));
If the Button class were strictly reference counted, it would begin with a count of 1, and the creator of the button would own this reference. The Window would add an additional reference, bringing the total reference count to 2. Thus the author of the above code would be required to call unref() on the button; in other words, to avoid memory leaks with strict reference counting the following code would be required:
  Window * win = new Window;
  Button * button = new Button ("My Button");
  win->add (button);
  button->unref ();
Needless to say, this is fairly cumbersome. With the floating reference count, when a child widget is added to a container, the container calls ref () on the child (as it would with strict reference counting), but it also calls sink(). The call to sink() removes the initial floating reference, leaving only one reference. When the container is destroyed, this single reference is removed and the container's children are destroyed along with it.

The ptr<T> smart pointer class is intended for use with floating-reference objects. ptr<T> will call ref() and then sink() on any object assigned to the pointer. strict_ptr<T> may also be used with these objects; however it will never call sink (), only ref(). strict_ptr<T> is useful if you don't want to change the floating status of an object, but it risks memory leaks, because strict reference counting is very hard to use without leaking memory.

The following code works nicely with floating references and ptr<T>, in constrast to strict_ptr<T> and strict references:
  ptr<Button> button = new Button;  
The button starts life with a reference count of 1, but this reference is floating. The ptr<Button> calls ref () then sink(), adding a reference but removing the floating reference. The only reference remaining is the single reference owned by the smart pointer; no memory will be leaked.

Here are some of the rules floating reference counted objects follow: