create() - create reference-counted objects

#include <x/ref.H>
#include <x/ptr.H>

class buttonObj : virtual public x::obj {

public:
    buttonObj(int width, int height);
    ~buttonObj();

// ...

};

typedef x::ref<buttonObj> button;
typedef x::ptr<buttonObj> buttonptr;

button quit(button::create(100, 100));

An x::ref and an x::ptr defines a member typedef named base. This is a typedef to a class with static methods, or other members that are provided by the x::ref or the x::ptr, to supplement the class * and -> method operators. An x::ref's and x::ptr's create() is actually a call to base::objfactory<T>::create(), with T being the x::ref or a x::ptr type that's calling it, and is the expected return type from create(). By default, base gets typedef-ed to x::ptrref_base, which defines the objfactory template class parameter with a static create() method that constructs a new object, for the x::ref or the x::ptr.

x::ref's and x::ptr's create() method forwards its arguments to base::objfactory<T>::create(). The default implementation, x::ptrref_base::objfactory<T>::create(), constructs the object on the heap with new, and forwards the arguments to the object's constructor (and optionally calls constructor() too). In nearly all cases, it's sufficient to define a constructor in the reference-counted subclass of x::obj, but it's possible to define a custom base with a create() that does something else.

Reference-counted objects do not get explicitly deleted, as this is done by the reference-counting templates; and create() removes all the news too. With create(), x::ref, and x::ptr, an application that uses LibCXX will not have any news and deletes. Outside of create(), LibCXX itself has a grand total of two explicit news, to allocate two low-level objects before most of its classes get initialized.

Note

create() is required to create subclasses of x::obj. An explicit new, and assigning the result to an x::ref or an x::ptr will not work. Assigning a native pointer, to an existing x::obj subclass instance, to an x::ref or an x::ptr is permitted, and has the expected result of incrementing the internal reference count.

Range-based iteration on reference-counted objects

It can be convenient to use a reference-counted object with a begin() and end(), like an x::weakmap, as a range iterator:

typedef x:ptr<widgetObj> widgetptr;

typedef x::weakmap<std::string, widgetObj> weakwidgetmap;

weakwidgetmap get_current_widgets();

auto current_widgets = get_current_widgets();

// ...

for (auto widget: *current_widgets)
{
    // ...
}

Note the need to dereference current_widgets since, for all practical purposes, it's a pointer. begin() and end() gets implemented in the object it points to.

Note

This shorter alternative seems intuitive, but it's actually ill-formed:

for (auto widget: *get_current_widgets())
{
    // ...
}

Range iteration uses rvalue fereferences. The reference from create() goes out of scope and gets destroyed, but the rvalue reference remains in scope, and gets invoked for the begin() and the end(). C++11 defines range iteration as equivalent to (roughly speaking).


auto && range=*get_current_widgets();

for (auto iter=range.begin(); auto != range.end(); ++iter)
{
    // ...
}

get_current_widgets() returns a reference-counted object. * dereferences, and leaves it as an rvalue reference. The reference then gets destroyed, at the end of the sequence point, and as it's the only reference to the reference-counted object, it gets destroyed. Meanwhile, the rvalue reference, to the destroyed object remains, producing ill-formed results.

Rule of thumb to follow: when using the * operator to dereference a reference-counted object for a container-based range operation, the * operator should operate on an lvalue, and never an rvalue.