Cross-Platform C++

ot
class RefPtr< T >

#include "ot/base/RefPtr.h"

Template class that helps to implement the ManagedObject reference-counting scheme.

RefPtr is a template class used to help implement the reference-counting scheme for instances of ManagedObject. ManagedObject instances can be used without the help of a RefPtr handle, but using RefPtr helps to alleviate most of the tedious and potentially error-prone reference-counting tasks.

When a RefPtr is constructed or assigned, it automatically increments the reference count of its associated object by calling ManagedObject::addRef(). When a RefPtr is destroyed, its destructor automatically decrements its associated object's reference count by calling ManagedObject::release().

The ManagedObject reference-counting scheme provides shared ownership semantics, where the lifetime of the object is guaranteed to last until all the references to it have been destroyed. It is safe to pass RefPtrs to functions and to store them within standard C++ collections.

The RefPtr class has a user-defined operator->() which allows it to be used as if it were a raw C++ pointer. Here's a simple example:

    RefPtr<InputStream> rpInputStream = new FileInputStream(OT_T("foo.txt"));
    RefPtr<Reader> rpReader = new InputStreamReader(rpInputStream.get());
    IntType x = rpReader->read();

In the example, all reference-counting is managed by RefPtrs, and the pointer operator was used to access the read() function. The rp prefix is a convention used throughout OpenTop when declaring RefPtr variables.

RefPtr has been modelled so that it can be used in a similar way to a raw C++ pointer, with the important exception that there is no implicit conversion from a RefPtr to a raw pointer. There is an automatic conversion to type bool which allows for the common practice of testing a null pointer like so:

    RefPtr<Thread> rpThisThread = Thread::CurrentThread();
    if(rpThisThread) {
        // This thread was created under the control of a Thread object
        ...
    }

When should RefPtr<T> be used?

Function return values

Functions wishing to return a pointer to a ManagedObject should instead return a RefPtr. This has the advantage that the calling function does not need to worry about the reference count, it is exception-safe and can be particularly advantageous if the calling function simply wants to pass the result as a parameter to another function like this:

    String sHost = OT_T("www.elcel.com");
    RefPtr<Socket> rpSocket = new Socket(InetAddress::GetByName(sHost).get(), 1234);

In the above code fragment, the Socket constructor was passed a pointer to an InetAddress which was returned from InetAddress::GetByName(). Actually, InetAddress::GetByName() returns a RefPtr<InetAddress> which ensures the reference remains valid for the scope of the statement. The RefPtr<InetAddress> is explicitly converted into a raw pointer by the RefPtr::get() method.

Another advantage of returning a RefPtr from a function is that function calls can be chained together. For example:

    String sName = rpSocket->getLocalAddress()->getHostName();

In the above code fragment, getLocalAddress returned a RefPtr<InetAddress> which was used in-situ to call getHostAddress(). The RefPtr<> ensures that the reference count of the InetAddress is properly maintained without adding complexity to the application.

Function input/output parameters

Function input parameters are not required to use RefPtrs; raw C++ pointers are generally more efficient and perfectly adequate in this case. Function output parameters, however, should be declared as non-const RefPtrs by reference. For example, the following function makes use of return parameters to connect and return 2 network sockets:-

    bool getSockets(const String& inStr, RefPtr<Socket>& rpOutSock1, RefPtr<Socket>& rpOutSock2)
    {
        bool bRet = true;
        try
        {
            rpOutSock1 = new Socket(inStr, 123);
            rpOutSock2 = new Socket(inStr, 456);
        }
        catch(SocketException& e)
        {
            bRet = false;
            rpOutSock1.release();
            rpOutSock2.release();
        }
        return bRet;
    }

Variables

Generally, the only place where raw pointers are used is in function input parameters. Elsewhere, such as stack variables and class members, RefPtrs should be used instead. This has the advantage that custom destructors are not required and reference counting is automatic. For example, here is the definition for a class that holds a counted reference to an InputStream object:

    class foo
    {
    public:
        foo(InputStream* pInputStream) : m_rpInputStream(pInputStream) {}
    private:
        RefPtr<InputStream> m_rpInputStream;
    };

In this example the class foo has no need for a custom destructor, the reference count of the contained InputStream will be managed by the RefPtr member.

Note, however, that if an object instance ever tried to store a reference to itself it would create a tight cyclic reference with the result that the reference count would never be decremented to zero. If this is a possibility, use the RefPtrMember<T> class which has been customized to detect and avoid this behaviour.

Automatic conversion

After much deliberation, the OpenTop designers decided against providing RefPtr with a conversion operator to allow it to be implicitly converted into a raw C++ pointer. Providing such a conversion operator would have made the syntax for passing RefPtrs to functions simpler and more elegant, but it would also have allowed RefPtrs to be assigned to raw C++ pointers, a trap that inexperienced developers could all-too-easily fall into. For example, the following code is incorrect because it attempts to convert a RefPtr into a raw C++ pointer.

    // The following line will not compile...
    InetAddress* pAddr = InetAddress::GetByName(OT_T("www.elcel.com"));
    // ...but if it did, the following line would cause an error
    String sHost = pAddr->toString();

If we had provided a conversion operator, the above code would have compiled successfully, and the program would probably crash (or worse) when the pAddr variable was dereferenced. This is because InetAddress::GetByName() returns a RefPtr<InetAddress> which, because it is not bound to a reference, will be immediately destroyed with the result that the InetAddress to which it refers will be destroyed also. Of course the correct way to code this example is with a local RefPtr variable:-

    RefPtr<InetAddress> rpAddr = InetAddress::GetByName(OT_T("www.elcel.com")); 
    String sHost = rpAddr->toString();

See also:
RefPtrMember , ManagedObject



Constructor/Destructor Summary
RefPtr()
         Default constructor.
RefPtr(const RefPtr< T >& rhs)
         Constructs a RefPtr from another RefPtr with the same object type.
RefPtr(T* ptr)
         Constructs a RefPtr with a pointer to T.
~RefPtr()
         Destructor.

Method Summary
 T* get() const
         Returns the contained object pointer.
 bool isNull() const
         Tests if the contained object pointer is null.
 T& operator *() const
         A dereferencing operator.
  operator bool() const
         Conversion operator.
 bool operator!=(const RefPtr< T >& rhs) const
         Inequality operator.
 bool operator!=(const T* rhs) const
         Inequality operator.
 bool operator<(const RefPtr< T >& rhs) const
         Less than operator.
 RefPtr< T >& operator=(const RefPtr< T >& rhs)
         Assigns one RefPtr to another.
 RefPtr< T >& operator=(T* ptr)
         Assigns a pointer.
 bool operator==(const RefPtr< T >& rhs) const
         Equality operator.
 bool operator==(const T* rhs) const
         Equality operator.
 T* operator->() const
         A dereferencing operator.
 void release()
         Decrements the reference count of the contained object pointer if it is not null, before setting it to null.

Constructor/Destructor Detail

RefPtr

 RefPtr()
Default constructor. The internal object pointer is initialized to null.


RefPtr

 RefPtr(const RefPtr< T >& rhs)
Constructs a RefPtr from another RefPtr with the same object type. If rhs contains a non-null object pointer, addRef() is called to increment the reference count.

Parameters:
rhs - the RefPtr<T> to copy.

RefPtr

 RefPtr(T* ptr)
Constructs a RefPtr with a pointer to T. If ptr is not null, addRef() is called to increment the reference count.

Parameters:
ptr - pointer to an object of type T, which is usually a class derived from ManagedObject.

~RefPtr

 ~RefPtr()
Destructor. Decrements the reference count of the contained object pointer if it is not null.


Method Detail

get

T* get() const
Returns the contained object pointer. Neither the RefPtr nor the reference count of its object are changed.


isNull

bool isNull() const
Tests if the contained object pointer is null.

Returns:
true if the object pointer is null; false otherwise

operator *

T& operator *() const
A dereferencing operator. Returns the contained object. This operator allows RefPtrs to be used as if they were raw C++ pointers.


operator bool

 operator bool() const
Conversion operator.

Returns:
true if this RefPtr is not equal to null. See the class description for further information about using the conversion operator.

operator!=

bool operator!=(const RefPtr< T >& rhs) const
Inequality operator. Returns true if this RefPtr refers to a different object than rhs. If this and rhs both refer to null, false is returned.

Parameters:
rhs - the RefPtr to compare.

operator!=

bool operator!=(const T* rhs) const
Inequality operator. Returns true if this RefPtr refers to a different object than rhs. If this and rhs both refer to null, false is returned.

Parameters:
rhs - a pointer to an object of type T which will be compared against the contained pointer

operator<

bool operator<(const RefPtr< T >& rhs) const
Less than operator. Returns true if this RefPtr should be ordered before rhs. If this and rhs both refer to null, false is returned.

Parameters:
rhs - the RefPtr to compare.
Since:
1.3

operator=

RefPtr< T >& operator=(const RefPtr< T >& rhs)
Assigns one RefPtr to another. If rhs contains a non-null object pointer, addRef() is called to increment the reference count.

Parameters:
rhs - the RefPtr<T> to copy.

operator=

RefPtr< T >& operator=(T* ptr)
Assigns a pointer. If ptr is not null, addRef() is called to increment the reference count. If this RefPtr previously referenced an object, release() is called on that object.

Parameters:
ptr - pointer to an object of type T

operator==

bool operator==(const RefPtr< T >& rhs) const
Equality operator. Returns true if this RefPtr refers to the same object as rhs. If this and rhs both refer to null, true is returned.

Parameters:
rhs - the RefPtr to compare.

operator==

bool operator==(const T* rhs) const
Equality operator. Returns true if this RefPtr refers to the same object as rhs. If this and rhs both refer to null, true is returned.

Parameters:
rhs - a pointer to an object of type T which will be compared with the contained pointer

operator->

T* operator->() const
A dereferencing operator. Returns the contained object pointer. This operator allows RefPtrs to be used as if they were raw C++ pointers.


release

void release()
Decrements the reference count of the contained object pointer if it is not null, before setting it to null.



Cross-Platform C++

Found a bug or missing feature? Please email us at support@elcel.com

Copyright © 2000-2003 ElCel Technology   Trademark Acknowledgements