Topic: strings, reference counting, and re-entrancy


Author: brad.daniels@missioncritical.com (Brad Daniels)
Date: 1997/08/27
Raw View
I wanted an efficient string class, so I started looking at the C++
basic_string template.  The documentation (in Microsoft's DevStudio) said
nothing about reference counting, so I was thinking I'd have to deal with
implementing refernce counted strings myself.

I started looking at the actual code, and saw functions like _Refcnt() and
_Split().  "Aha!"  I thought.  "Maybe I don't have to reference count these
suckers myself!"  The I noticed that the reference counting is
non-reentrant.  I tried to think of ways to hook some kind of mutex in, but
nothing came to mind.  Also, I really don't want to depend on an
unpublished implementation detail.  I'm now a bit bummed.

At my previous job, we used Rogue Wave's RWCString class, which was
reference counted and re-entrant, but that's the only class I want out of
Rogue Wave, and the per-developer price tag seems a bit high for just a
string class.

I'm sure others out there have run into this kind of problem.  How did you
resolve it?

Also, I notice that auto_ptr doesn't do reference counting.  Why is there
no reference counting template class in the standard?  It's not that hard
to implement something similar to auto_ptr.  Of course, to implement a good
reference counting template, you want one of the template parameters to be
a mutex class (which can be a dummy class for the non-re-entrant case.)

- Brad
----------------------------------------------------------------------------
Brad Daniels                  |  Was mich nicht umbringt macht mich hungrig.
Mission Critical Software     |   - Otto Nietzche
Standard disclaimers apply    |     (Friedrich's corpulent brother)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: haberg@matematik.su.se (Hans Aberg)
Date: 1997/08/28
Raw View
In article <34049319.434148765@news1.alterdial.uu.net>,
brad.daniels@missioncritical.com (Brad Daniels) wrote:

>..  Why is there
>no reference counting template class in the standard?

  I have used a reference count extensively in C++, as a means of avoiding
having to implement a complicated garbage cleaner. First note that
reference counts are slow; I use it only to create references (= pointers)
that clean up by themselves, instead of doing it by hand in C++.

  The second thing is that C++ does not properly separate l-values and
r-values, so I found it nearly impossible to keep in my mind when
something should be cloned. It looked as though one would need to separate
the copy constructors
    T::T(const T&)
    T::T(T&)
but the C++ standard is such that it does not keep track of this in a way
that it would work with reference counts. (So you have to keep track of
this in your head, which is virtually hopeless.)

  I could only use it, because I happened to work on a language that
properly separates l- and r-values.

  So there seems to be good reasons for not using reference counts in C++:
Support for garbage cleaners would be better.

  Otherwise, there are some interesting ways of implementing ref counts in
C++: The best way I found, is to let the objects delete themselves. In
order to illustrate this idea, I enclose some code I stripped out of my
program (so it may be somewhat messy). (See below.)

  The data you want to ref count is of type T. In the version below, the
ref count class DataRef maintains a pointer to T, but one could also have
    class DataRef {
        T dp;
        ...   }
or derive
    class DataRef : T {
       ...  }

  Then, the clever thing is that DataRef can also be used as a regular
automatic data class:
    DataRef dr;
    ...
as the refcount is set to 1 in such cases. Therefore it is easy to mix
automatic data "DataRef()" with refcount data "Data(new RefCount)".

  I hope the ideas can be extracted from the example below. Unfortunatley,
I could not find a more concise example.

  Hans Aberg


-- Example -- Snip -- Snip -- Snip ----------------------------------

class DataRef
{
    friend class Data;

    unsigned count;

    T* dp;

    // Data you want to be reference counted

public:
    DataRef() : count(1), data(new T) { }  // Default constructor
    ~DataRef() { data->shed(); }                // Destructor

    DataRef(const DataRef& dr)                  // Copy constructor
     : count(1), data(dr.data->copy()) { }

    DataRef& operator=(const DataRef& da)       // Assignment
    {   // Warning: "da.data" may be a reference to a subpart of "data";
therefore
        // "da" must be copied before "data" is being deleted.
        T* dp = da.data->copy(); data->shed(); data = dp;
        return *this;   }

    // Copier; return clone/reference as subobjects deem fit.
    DataRef* copy() const
    {   return new DataRef(data->copy());   }

    // Clone; return an independent copy.
    DataRef* clone() const
    {   return new DataRef(data->clone());   }

    DataRef* reference() const      // Reference copier, increasing
reference count.
    {   ((DataRef*)this)->count++;  return (DataRef*)this;   }

    DataRef* shed()         // Shed (remove) this copy from reference cluster
    {   if (count <= 0)  { cerr << "DataRef shed count 0." << endl; }
        if (--count == 0)  { delete this; return NULL; }
        return this;   }


    // If multiple reference, return a reference to a clone
    // To detach  DataRef* data, write  data = data->detach()
    DataRef* detach()
    {   if (count > 1) { shed(); return clone(); }   return this;  }

    DataRef(const T& de)       // Conversion constructor; clones data.
     : count(1), data(de.clone()) { }

    // DataRef must be constructed with new, copy(), or clone()
    DataRef(T* dp)         // Conversion constructor
     : count(1), data((dp != NULL)? dp : new T) { }
};


class Data
{
    friend class DataRef;

    typedef DataRef DRef;

    DRef* dref;

public:
    Data() : dref(new DRef) { }         // Default constructor
    ~Data() { dref->shed(); }           // Destructor

    Data(const Data& da)                    // Copy constructor
     : dref(da.dref->reference()) { }

    Data& operator=(const Data&);           // Assignment

private:
    Data(DRef* drp) : dref(drp) { }

public:

        // Copier; return clone/reference as subobjects deem fit.
    Data copy() const
    {   return Data(dref->copy());   }

        // Clone; return an independent copy.
    Data clone() const
    {   return Data(dref->clone());   }

    // Detach *this object; that is, if reference count is more than one,
    // make *this a clone; return a reference to *this.
    Data detach()
    {   dref = dref->detach();  return Data(dref->reference());   }

    // More Stuff
};


-- End-Of-Example -- Snip -- Snip -- Snip ----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Steve Clamage <stephen.clamage@Eng.Sun.COM>
Date: 1997/08/28
Raw View
Brad Daniels wrote:
>
> Also, I notice that auto_ptr doesn't do reference counting.  Why is there
> no reference counting template class in the standard?

A reference-counted version of auto_ptr was proposed at the same
time as auto_ptr, but was rejected. The proposal (if I remember it
correctly) was an intrusive reference counter, and that is often
not suitable.

Upon further reflection, I think a counted-pointer proposal should
present a family of reference-counted auto_ptrs to satisfy the
range of useful implementations of reference counting. No one
ever submitted such a proposal, unfortunately.

--
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Nathan Myers <ncm@-nospam-cantrip.org>
Date: 1997/08/29
Raw View
Steve Clamage wrote:
> Brad Daniels wrote:
> > Also, I notice that auto_ptr doesn't do reference counting.
> > Why is there no reference counting template class in the standard?
>
> A reference-counted version of auto_ptr was proposed at the same
> time as auto_ptr, but was rejected. The proposal (if I remember it
> correctly) was an intrusive reference counter, and that is often
> not suitable.

In fact, the proposal was a rather complicated template offering
both intrusive and non-intrusive options.  It was rejected partly
because it was more complicated than most people thought such a
facility should be.

> Upon further reflection, I think a counted-pointer proposal should
> present a family of reference-counted auto_ptrs to satisfy the
> range of useful implementations of reference counting. No one
> ever submitted such a proposal, unfortunately.

Such a proposal would probably have passed, at the time.  As I
recall, people expected the British Standards Institute members
who were requiring support for something like that to come
forward with a proposal, but they never did.

Nathan Myers
ncm@cantrip.org
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]