|
ADTF
|
The uCOM offers some functionality to share ownership of objects through pointers.
For this purpose, the STL offers several so called smart pointers, e.g. std::shared_ptr, std::weak_ptr or std::unique_ptr.
However, these smart pointers do have the major drawback that they cannot be used to share resources between binary boundaries. E.g. compiling an STL smart pointer in release mode leads to an entire different object layout than in debug mode.
To realize a shared ownership even between binary boundaries, the uCOM offers an own reference counting mechanism which is implemented with object_ptr and iobject_ptr.
To use reference counting on objects through pointers with object_ptr and iobject_ptr, some things must be kept in mind:
IObjectmake_object_ptr() must be useducom_cast()Given the following inheritance hierarchy (taken from uCOM Cast):
To create an object_ptr managing the ownership of an object cCar through a pointer of IVehicle one would have to use make_object_ptr().
Of course, const correctness is provided:
make_object_ptr() is intended to work exactly like std::make_shared().
The parameters are directly forwarded to the constructor of cCar during construction. No 'traditional' memory allocation is needed by the user, so no new or malloc must be called.
In fact, make_object_ptr() is the only way to instantiate a new reference counted object. make_object_ptr() returns the allocated object with a reference count of 1.
object_ptr offers several constructors and assignment operators.
This makes it possible to 'convert' one object_ptr managing type A to another one managing type B - as long as type A is castable to type B with ucom_cast().
In this example the managed resource cCar gets casted to IVehicle in the aliasing constructor of object_ptr. This makes the instantiation of object_ptr instances managing objects through interface pointers very convenient.
With the reference counting wrapped into object_ptr, the developer doesn't need to take care of reference counting at all.
Copying, moving, deleting and creating object_ptr instances entirely takes care of the lifetime of the managed object under the hood.
Just like std::shared_ptr objects, the managed object is destroyed and its memory deallocated when either of the following happens:
object_ptr owning the object is destroyed, orobject_ptr owning the object is assigned another pointer via object_ptr::operator= or object_ptr::Reset()The managed object is destructed and deallocated using the supplied IObject::Destroy() method.
In fact, the object_ptr is the only class having access to this method, restricting object (de-)allocation of type IObject to just make_object_ptr() and object_ptr.
To ensure binary compatible reference counting, pure abstract base class iobject_ptr is introduced. If a reference counting is required in interface methods, this class is the parameter type to use.
object_ptr being derived from iobject_ptr implicit upcasting and convenient usage on calling functions.
object_ptr also implements a conversion operator to iobject_ptr<IObject> or iobject_ptr<const IObject>, depending on the constness of the managed object type (object_ptr_base).
Thus, code like this is totally valid:
Using this mechanism in functions or methods ensures an entirely binary compatible reference counting.
The following code shows an example how this might be used:
Main purposes of object_ptr and iobject_ptr are to
Despite the fact, that it might be used as a more generalized reference counting mechanism, these requirements limit the usage of object_ptr and iobject_ptr to objects of types derived from IObject.
To fulfill the first requirement, object_ptr calls the IObject::Destroy() method to ensure the deallocator is called in the same DLL as the object was allocated.
To fulfill the second requirement, object_ptr uses the ucom_cast() which also only works on types derived from IObject.
Thus, code like this won't compile:
IStatusSymbol can not be used as managed resource as it is not derived from IObject.