Back to FlowSsh Documentation

RefPtr and RefPtrConst

[C++]

template <class T>
class RefPtrConst : public RefData<T>
{
public:
  RefPtrConst() {}
  RefPtrConst(T const* ptr);    // No AddRef() here
  ~RefPtrConst();               // Release() called
  
  // Copy operator
  RefPtrConst<T>& operator= (T const* ptr);            // No AddRef() here
  RefPtrConst<T>& operator= (RefPtrConst<..> refPtr);  // AddRef() called
  
  void Reset();                 // Release() called; the wrapped object is detached
  
  // Accessors
  T const* Get() const;
  T const* operator-> () const;
  T const& GetRef() const;
}


template <class T>
class RefPtr : public RefPtrConst<T>
{
public:
  RefPtr() {}
  RefPtr(T const* ptr);    // No AddRef() here
  
  // Copy operator
  RefPtr<T>& operator= (T const* ptr);       // No AddRef() here
  RefPtr<T>& operator= (RefPtr<..> refPtr);  // AddRef() called
  
  // Accessors
  T const* Get() const;
  T const* operator-> () const;
  T const& GetRef() const;
}

Remarks

RefCountable and IRefCountable. In FlowSshCpp, all objects derived from RefCountable and IRefCountable are reference counted objects. The following rules outline the usage guidelines for them:

  1. Always create them on the heap (dynamic allocation).
  2. Never delete them. They provide AddRef and Release calls similar to those found in COM objects. FlowSshC will automatically destroy these objects after their reference count drops to 0.
    Important: These objects are destroyed when both the user AND the library have released them. When the user releases an object before the library does, the object will continue to exist until it is released by the library. During this time, its handlers may still be called.
  3. Use our convenient RefPtr. Example:
        RefPtr<Client> client(new Client);
    RefPtr manages the necessary AddRef and Release calls of the wrapped object. On occasions where you cannot use RefPtr, be sure to call AddRef and Release as appropriate.

RefPtr and RefPtrConst. The declaration at the beginning of this document clearly shows that RefPtr and RefPtrConst are related and provide virtually the same functionality. What is important to understand is that none of their constructors implies an AddRef call. Similarly, if you try to assign a raw ordinary pointer to RefPtr or RefPtrConst, AddRef is not called either. The following example demonstrates this.

function Erroneous()
{
  Client* rawPtr = new Client();    // RefCount=1

  RefPtr<Client> refPtr1(rawPtr);   // RefCount=1
  RefPtr<Client> refPtr2 = rawPtr;  // RefCount=1

  // refPtr2->AddRef();             // fix - manually call AddRef
}

In the sample the reference count for our client object remains 1 all the time. Nevertheless, the object is assigned to two reference pointers. As soon as these pointers go out of scope, they both try to Release the object and thus delete it from memory as the reference count drops to zero. Obviously, deleting the same object twice results in an access violation crash. To fix the code we could manually increase the reference count via AddRef. Alternatively, we can conveniently assign the first refPtr1 to refPtr2 directly. In this case, the reference count is implicitly increased and handled correctly. The next example demonstrates this.

function Working()
{
  RefPtr<Client> refPtr1(new Client());  // RefCount=1
  RefPtr<Client> refPtr2 = refPtr1;      // RefCount becomes 2
}

As the function goes out of scope first refPtr2 is destructed; the destructor of refPtr2 calls Release on the client, dropping its reference count to 1. Right thereafter refPtr1 is destructed; at this point the reference count of the client drops to zero and it is deleted from memory.

Accessors. There are several accessors available for RefPtr and RefPtrConst. Get returns a raw pointer and GetRef a reference to the wrapped object. Though, most of the times you will simply use the operator->. It lets you access the wrapped object as if using an ordinary raw pointer.

function Accessors()
{
  RefPtr<Client> refPtr(new Client());

  Client* rawPtr = refPtr.Get();
  Client& refrnc = refPtr.GetRef();
  
  refPtr->SetUserName(L"myname"); // operator-> in action
}

RefPtr vs. RefPtrConst. You may wonder by now if there is a difference between RefPtr and RefPtrConst after all? In fact, the only difference is that RefPtrConst points to an object with constant content (imagine the "Client const* rawPtr;" as an equivalent). In other words, with RefPtrConst you can only invoke const methods of the wrapped object.