Open Search
    References

    About

    References are used to manage allocated objects and to reference-count these objects. For example, when all references to a given object are deleted, the object itself will be deleted. References are based on the maxon::BaseRef template.

    The following reference types are available:

    Using these reference templates, non-intrusive reference counting can be applied to any allocated object. A reference based alias implements a "Create()" function that allows the easy allocation of a new, reference counted instance.

    For safe access to a reference from multiple threads see maxon::ThreadSafeRef.

    Pointer

    maxon::Pointer is handling an ordinary C++ pointer.

    UniqueRef

    A maxon::UniqueRef stores a pointer to a given object. It will delete the object when itself is destroyed. Only one maxon::UniqueRef can have the ownership of a given object at a time.

    Note
    A maxon::UniqueRef object can be moved (using std::move()) but not copied.
    The const-ness of the maxon::UniqueRef object can be used to control access to the referenced object.
    // This example defines an alias for an UniqueRef managing a SimpleElement.
    // The alias is used to create a new, managed instance of SimpleElement.
    // define alias
    using ElementRef = maxon::UniqueRef<SimpleElement>;
    {
    // allocate a new element
    ElementRef ref = ElementRef::Create() iferr_return;
    // set data
    ref->_data = 123;
    // read data
    DiagnosticOutput("Data: @", ref->_data);
    // when the scope is left, UniqueRef and the allocated element are destroyed
    }
    Definition: baseref.h:62
    #define MAXON_SCOPE
    Definition: apibase.h:2841
    static auto Create(ARGS &&... args)
    Definition: apibase.h:2773
    #define DiagnosticOutput(formatString,...)
    Definition: debugdiagnostics.h:176
    #define iferr_return
    Definition: resultbase.h:1519
    // This example shows how a UniqueRef is used to manage a newly created object.
    // If the function fails, the UniqueRef will destroy the allocated object.
    // If the ownership could be transferred successfully, UniqueRef will release it.
    //----------------------------------------------------------------------------------------
    // Creates a SimpleElement object and adds it to the given PointerArray
    // @param[in] elements The array to store the new object.
    // @return maxon::OK on success.
    //----------------------------------------------------------------------------------------
    {
    // allocate new element
    // UniqueRef takes ownership
    // element is handed over to the PointerArray which will take ownership
    // if this operations fails, UniqueRef makes sure the allocated element is freed
    elements.AppendPtr(ref) iferr_return;
    // the PointerArray has taken ownership
    // UniqueRef must release ownership
    ref.Disconnect();
    return maxon::OK;
    }
    std::conditional< Bool(HANDLER::KIND &VALUEKIND::COW_MASK), typename std::remove_const< T >::type, T >::type * Disconnect()
    Definition: baseref.h:501
    Definition: pointerarray.h:43
    ResultPtr< T > AppendPtr(T *x)
    Definition: pointerarray.h:296
    return OK
    Definition: apibase.h:2690
    #define NewObj(T,...)
    Definition: newobj.h:108
    #define iferr_scope
    Definition: resultbase.h:1384

    maxon::AutoMem is an alias for maxon::UniqueRef handling raw memory maxon::RawMem. See also Memory Allocation.

    // This example uses AutoMem to manage the allocated memory.
    {
    // new elements are allocated, AutoMem takes ownership
    // data is filled
    for (maxon::Int i = 0; i < count; ++i)
    data[i]._data = i;
    // when the scope is left, AutoMem will delete the allocated memory
    }
    Py_ssize_t i
    Definition: abstract.h:645
    Py_ssize_t count
    Definition: abstract.h:640
    #define NewMemClear(T, cnt)
    Definition: defaultallocator.h:204
    Int64 Int
    signed 32/64 bit int, size depends on the platform
    Definition: apibase.h:188

    StrongRef, StrongCOWRef and WeakRef

    One or many maxon::StrongRef objects can reference a given object in memory. When all strong references to that object are destroyed, the object will be deleted.

    // This example stores the newly created object in a StrongRef.
    // The StrongRef takes ownership and deletes the object when itself is destroyed.
    // allocate object
    SimpleElement* const obj = NewObj(SimpleElement) iferr_return;
    // set data
    obj->_data = 123;
    {
    // strong reference takes ownership
    // print data
    DiagnosticOutput("Data: @", ref->_data);
    // when the scope is left, the StrongRef is destroyed
    // and with it the referenced object
    }
    // now "obj" has been freed
    PyObject * obj
    Definition: complexobject.h:60
    // This example defines an alias for a StrongRef managing a SimpleElement.
    // This alias can be used to create a new instance of that SimpleElement that
    // is owned by a StrongRef. A copy of the original StrongRef is then created.
    // The copy is pointing to the same data as the original.
    // defining an alias
    {
    // allocate the object
    const SimpleRef original = SimpleRef::Create() iferr_return;
    original->_data = 123;
    {
    // create a copy of the StrongRef
    const SimpleRef copy = original;
    // edit original data
    original->_data = 456;
    // "original" and "copy" are pointing to the same data
    DiagnosticOutput("@ : @", original->_data, copy->_data);
    // when the scope is left, SimpleRef "copy" is destroyed
    }
    // when the scope is left, SimpleRef "original" is destroyed
    // and the allocated object with it
    }

    A maxon::StrongRef can also manage raw memory:

    // This example manages the newly allocated memory
    // with a StrongRef that frees the memory at the end.
    {
    // allocate memory
    // data is filled
    for (maxon::Int i = 0; i < count; ++i)
    data[i]._data = i;
    // when the scope is left, the allocated memory is deleted
    }
    #define NewMem(T, cnt)
    Definition: defaultallocator.h:195

    A maxon::StrongCOWRef is the same as maxon::StrongRef but it supports copy-on-write techniques. As long as no reference is trying to modify the referenced object, all references point to the same object. When a reference wants to modify the object, the object is copied and the reference used for modification has ownership of that new object.

    // This example shows how a StrongCOWRef is used to manage objects.
    // The StrongCOWRef takes ownership of a newly created object.
    // Then a copy of the original StrongCOWRef is created. As long
    // as the data does not change, both the original and the copy
    // point to the same data. Only when the copy should be changed
    // using MakeWritable() will a new object be created.
    // defining an alias
    using SimpleCOWRef = maxon::StrongCOWRef<SimpleElement>;
    {
    // allocates the object
    SimpleElement* const data = NewObj(SimpleElement) iferr_return;
    // set data
    data->_data = 100;
    // StrongCOWRef takes ownership
    const SimpleCOWRef original(data);
    {
    // create a copy of the StrongCOWRef
    SimpleCOWRef copy = original;
    // edit original data
    data->_data = 200;
    // "original" and "copy" are pointing to the same data
    DiagnosticOutput("@ : @", original->_data, copy->_data);
    // make copy writeable; a new instance will be allocated, owned by "copy"
    SimpleElement& copyData = copy.MakeWritable() iferr_return;
    copyData._data = 300;
    // original and copy will now store different data
    DiagnosticOutput("@ : @", original->_data, copy->_data);
    // when the scope is left, StrongCOWRef "copy" is destroyed
    }
    // when the scope is left, StrongCOWRef "original" is destroyed
    // and the allocated object with it
    }

    A maxon::WeakRef points to an object owned by a maxon::StrongRef. When there are no more strong references, the object is deleted and the maxon::WeakRef returns a null reference.

    // This example uses WeakRefs to access data managed with a StrongRef.
    // define alias
    // allocate an element
    SimpleElement* const element = NewObj(SimpleElement) iferr_return;
    element->_data = 123;
    // prepare WeakRef
    {
    // StrongRef takes ownership
    const SimpleRef strongRef(element);
    // set WeakRef
    weakRef = strongRef;
    // WeakRef is valid
    if (weakRef)
    {
    // use WeakRef to access data
    const SimpleRef data = weakRef;
    DiagnosticOutput("Data: @", data->_data);
    }
    // when the scope is left, SimpleRef gets destroyed
    // and the allocated element will be freed
    }
    // now WeakRef points to nothing
    if (!weakRef)
    DiagnosticOutput("WeakRef invalid");
    Definition: weakref.h:164
    PyObject * element
    Definition: unicodeobject.h:1016

    Classes

    Instances of custom classes can be managed with maxon::BaseRef based reference types. If it is needed to modify the reference-counting behaviour one can implement the following functions in the custom class:

    • AddReference(): Is called when a reference to the object is added.
    • RemoveReference(): Is called when a reference to the object is removed.
    • CreateStrongReference(): Is called when a strong reference is added.
    • AddWeakReference(): Is called when a weak reference to the object is added.
    • InitialReference(): Sets the initial reference to a newly allocated object.

    This is typically used for:

    • debugging reference handling
    • reference counting with alien memory management
    • synchronization of a reference with a background object
    // This example shows a simple class that implements AddReference() and RemoveReference().
    // Within these functions the class manages its own reference counting.
    //----------------------------------------------------------------------------------------
    // A simple, reference counted object.
    //----------------------------------------------------------------------------------------
    class ReferencedElement
    {
    public:
    //----------------------------------------------------------------------------------------
    // Constructor.
    //----------------------------------------------------------------------------------------
    MAXON_IMPLICIT ReferencedElement()
    {
    _data = 0;
    }
    //----------------------------------------------------------------------------------------
    // Destructor.
    //----------------------------------------------------------------------------------------
    ~ReferencedElement()
    {
    _data = 0;
    }
    //----------------------------------------------------------------------------------------
    // Adds a reference to this instance.
    //----------------------------------------------------------------------------------------
    void AddReference() const
    {
    DiagnosticOutput("Add reference");
    // increase reference count
    }
    //----------------------------------------------------------------------------------------
    // Removes a reference pointing to this instance.
    // The object will be deleted if this was the last reference.
    //----------------------------------------------------------------------------------------
    void RemoveReference() const
    {
    DiagnosticOutput("Remove reference");
    // decrease reference count
    {
    // if the last strong reference was released,
    // delete the object
    }
    }
    maxon::Int _data;
    };
    Bool Inc()
    Definition: atomictypes.h:2056
    static StrongReferenceCounter & GetReferenceCounter(const void *object)
    Returns the reference counter for classes which do not implement custom AddReference/RemoveReference ...
    Definition: system.h:231
    #define MAXON_IMPLICIT
    Definition: apibase.h:172
    MAXON_ATTRIBUTE_FORCE_INLINE void DeleteConstPtrObj(T *o)
    Definition: newobj.h:190
    // This example uses the class ReferencedElement that manages its own reference counting.
    ReferencedElement* const element = NewObj(ReferencedElement) iferr_return;
    element->_data = 123;
    {
    // store in StrongRef, AddReference() will be called
    {
    // store in second StrongRef, AddReference() will be called
    const maxon::StrongRef<ReferencedElement> secondRef = firstRef;
    // when the scope is left, "secondRef" is deleted and
    // RemoveReference() is called
    }
    // when the scope is left, "firstRef" is deleted,
    // RemoveReference() is called and the element freed
    }

    Further Reading