|
OpenTop 1.3 | |||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | Cross-Platform C++ | ||||
SUMMARY: CONSTRUCTOR | METHOD | DETAIL: CONSTRUCTOR | METHOD |
#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 ... }
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.
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();
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(const RefPtr< T >& rhs)
rhs
- RefPtr(T* ptr)
ptr
- ~RefPtr()
Method Detail |
T* get() const
bool isNull() const
T& operator *() const
operator bool() const
bool operator!=(const RefPtr< T >& rhs) const
rhs
- bool operator!=(const T* rhs) const
rhs
- bool operator<(const RefPtr< T >& rhs) const
rhs
- RefPtr< T >& operator=(const RefPtr< T >& rhs)
rhs
- RefPtr< T >& operator=(T* ptr)
ptr
- bool operator==(const RefPtr< T >& rhs) const
rhs
- bool operator==(const T* rhs) const
rhs
- T* operator->() const
void release()
|
OpenTop 1.3 | |||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | Cross-Platform C++ | ||||
SUMMARY: CONSTRUCTOR | METHOD | DETAIL: CONSTRUCTOR | METHOD |