VISH
0.2
|
The MemCore library provides reference pointers of two flavors, "strong" and "weak" ones. A "strong" pointer is a pointer that keeps the objects alive, a "weak" pointer is one that only recognizes that an object has died. Strong and weak pointers in the MemCore library are intrusive, which means they can only operate on objects that have been derived from a special base class. Furthermore they allow implicit conversion into derived classes via run time type information within a class hierarchy. Moreover, every strong pointer in MemCore is also a weak pointer.
These features distinguish the MemCore reference pointers from e.g. similar counterparts in the boost library, and other implementations.
A class that supposed to be reference-countable, must be derived from a MemCore::ReferenceBase<> instance:
struct MyObject : MemCore::ReferenceBase<MyObject>
{
MyObject()
: MemCore::ReferenceBase<MyObject>(this)
{}
};
Only then reference pointers to this class may be used. Moreover, this should be the only pointers ever used for such class objects. Never use native pointers any more. Newly allocated objects must be assigned immediatly to a strong pointer, or bad things will happen:
RefPtr<MyObject> newObject = new MyObject();
Note that this code is self-complete. The object will automatically die once the reference pointer "newObject" ends its lifetime. The usuage of a "delete" statement is not just unnecessary, but an error, both a programming and design error. You can check your code for memory faults even without compiling it by doing a "grep delete *.cpp". If you find any delete statements in your code, you will have memory faults (and only under lucky circumstances have the impression that everything works, and all memory that you allocated by new also has been deleted correctly).
Note also, once reference pointers are used, never use native pointers again.
As mentioned before, any strong pointer is also a weak pointer. We may have code like this:
void func(const WeakPtr<MyObject>&what); void main() { RefPtr<MyObject> newObject = new MyObject(); func( newObject ); }
This operation is at no cost, as internally a strong pointer is derived from a weak pointer. Also, a weak pointer may be converted into a strong pointer implicitely:
void func(const WeakPtr<MyObject>&what) { RefPtr<MyObject> HaveIt = what; ... }
This has the benefit that within the given function the object is kept alive, but once the function is left, the object may die.
Weak and strong pointers may implicitely be converted within a class hierarchy. Consider an object derived from the aforementioned example:
struct DerivedObject : MyObject { int i; };
Note that class DerivedObject has no knowledge that it was derived from a reference-counteable object.
Application code may now operate on base pointers, given a derived pointer, exactly like it is possible with native pointers:
void func(const RefPtr<MyObject>&baseptr); main() { RefPtr<DerivedObject> newObject = new DerivedObject(); func( newObject ); }
Application code may furthermore easily discover the actual derived object, my simply assigning it to a derived pointer:
void func(const RefPtr<MyObject>&baseptr) { RefPtr<DerivedObject> newObject = baseptr; if (newObject) { // newObject is a DerivedObject // we may assign its data members newObject->i = 42; } }
This code is similar to using native pointers in conjunction with dynamic_cast<> (which actually is more effortsome).
Note that we frequently use a shortcut of the if-condition, as C++ allows to declare a variable within the if-statement itself - a not very frequently used C++ feature, but quite convenient for compact codes. It also reduces the lifetime of the involved objects and thus improves performance:
void func(const RefPtr<MyObject>&baseptr) { if (RefPtr<DerivedObject> newObject = baseptr ) { // newObject is a DerivedObject // we may assign its data members newObject->i = 42; } }
This code is equivalent to the code before, but uses one line less.
All reference pointers can be assigned a null value to indicate that they are invalid:
MemCore::RefPtr<MyObject> Ptr = MemCore::NullPtr();
This is the default for uninitialized pointers. For checking the validity of a pointer, it may implicitely be converted into a bool type. There is not need to compare a pointer with a NullPtr().
Any reference counted object contains a weak pointer that relates to itself, as provided by the member function self() . It may be used to convert an instance of an object to a reference pointer of this object, or during construction of an object. The self-pointer is the reference-counter equivalent of the native "this" pointer. Its usage should however be avoided and be limited only to special cases.