Use copy semantics wherever possible

By using the surrogate techniques discussed in "Surrogate objects" on page 121, it's possible to use copy semantics with a reference-based implementation. Of course, this has higher overhead, sometimes too high to allow copy semantics. Even then, it's possible to use reference counting, but be careful to get the implementation right or you will have storage leaks. Use the Taligent MReferenceCounted class to implement reference counting; it is fast and multithread safe.

Although it is possible to reference-count objects without a surrogate object, it's more error prone. The trick is to correctly increment or decrement the count whenever and wherever necessary. Using a surrogate object lets C++ do the work.

A counted pointer can either be exposed directly to clients or embedded inside a surrogate as an implementation technique. Here is a simple example of a counted pointer template to illustrate the technique:

      template<class T> class TCountedPointer {
      public:
          TCountedPointer() { fPointer = NIL;};
          operator T* () const { return fPointer;};           // Dangerous!
          T* operator ->() const { return fPointer;};        // Safer
          TCountedPointer(const TCountedPointer& other)
              { fPointer=other.fPointer; fPointer->AddReference();};
          TCountedPointer(T* p) { fPointer = p; p->AddReference();};
          TCountedPointer &operator =(const TCountedPointer& other) 
              {
              T* old = fPointer;
              fPointer=other.fPointer;
              fPointer->AddReference();
              old->RemoveReference();
              };
          TCountedPointer &operator =(T* p)
              {
              T* old = fPointer;
              fPointer=p;
              p->AddReference();
              old->RemoveReference();
              };
      private:
          T* fPointer;
      };
Notice that defining the coercion operator to T* is dangerous because it creates ordinary pointers. Because those ordinary pointers aren't counted, they can become dangling references later on. It is safer to define the appropriate operators on your counted pointer type (unary*, unary->, and []). Then it's impossible to create an ordinary pointer from a counted pointer. If you additionally override unary & on the actual object to return a counted pointer instead of a regular pointer, you should only have counted pointers. Though it is impossible to prevent references from being used, they are less error prone.

Several references in the Bibliography describe this technique and give more examples.


[Contents] [Previous] [Next]
Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.

Generated with WebMaker