Topic: mutable & copy constructors


Author: dHarrison@worldnet.att.net (Doug Harrison)
Date: 1999/01/07
Raw View
Siemel Naran wrote:

>The "auto_ptr" is good for use inside a function.  It prevents memory
>leaks in the face of exceptions.  The "auto_ptr" is sometimes good
>as a member of a class, but this is a less strong argument because
>the class can have a destructor that properly releases memory.  In
>this case, the "auto_ptr" is useful for preventing memory leaks in
>the constructor.  And "auto_ptr" is sometimes good for return
>value, although now we can't get covariant return types.

As I said, lo those many months ago (26-Jul-98), given a non-copyable smart
pointer (nc_ptr), and a reference-counted smart pointer (rc_ptr) that
supports copying properly, I've found little use for std::auto_ptr. In the
scenarios you described, I use nc_ptr inside functions, nc_ptr or rc_ptr
inside classes, depending on the copy semantics of the containing class, and
rc_ptr for return values. I like this nc_ptr/rc_ptr dichotomy, because
nc_ptr is only as powerful as it needs to be, and in comparison to auto_ptr,
rc_ptr is harder to use incorrectly and is suitable for use as a class
member or container element. Also, both these classes are parameterized on
deletion traits, making them more generalized than auto_ptr.

To moderator: Did y'all stuff the first message in this thread in a bottle
and cast it into the sea or what? :)

[ moderator's note: If you mean that the original article in the
  series didn't appear on your news server, well, sometimes articles
  get lost. For example, in newsgroups that carry binaries, where
  people often post large files in several parts, it is common for
  one or more parts to be missing, even though they were all posted
  at the same time from the same server.

  There is no central distribution point for news articles -- they
  just get propagated in a somewhat arbitrary fashion. If you see
  replies to an article, you know that it appeared somewhere, even if
  not at your site. -sdc ]


--
Doug Harrison
dHarrison@worldnet.att.net


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: dHarrison@worldnet.att.net (Doug Harrison)
Date: 1999/01/08
Raw View
Doug Harrison wrote:

>[ moderator's note: If you mean that the original article in the
>  series didn't appear on your news server, well, sometimes articles
>  get lost. For example, in newsgroups that carry binaries, where
>  people often post large files in several parts, it is common for
>  one or more parts to be missing, even though they were all posted
>  at the same time from the same server.
>
>  There is no central distribution point for news articles -- they
>  just get propagated in a somewhat arbitrary fashion. If you see
>  replies to an article, you know that it appeared somewhere, even if
>  not at your site. -sdc ]

I didn't find my original article from 26-Jul-98 on Deja News, either. It's
no big deal; I just find a one-time, 5 month propagation delay amusing!

--
Doug Harrison
dHarrison@worldnet.att.net


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Carlo Wood <ca231196@runaway.xs4all.nl>
Date: 1999/01/10
Raw View
This is a multi-part message in MIME format.
--------------E9CC40392CB5E219A89BBC6A
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I think I had a similar problem once, and then I wrote
a lockable_auto_ptr.  I hereby donate that to the
internet community.  If someone ever wants to distribute
it further, please add a GPL header (I am lazy now).

Carlo Wood
--------------E9CC40392CB5E219A89BBC6A
Content-Type: text/plain; charset=us-ascii;
 name="lockable_auto_ptr.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="lockable_auto_ptr.h"

// $Header: /usr/src/CVS/libr/include/libr/lockable_auto_ptr.h,v 1.1 1998/11/24 15:08:15 carlo Exp $
//
// Author:
//
// 1024/624ACAD5 1997/01/26 Carlo Wood, Run on IRC <carlo@runaway.xs4all.nl>
// Key fingerprint = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
// Get key from pgp-public-keys server or
// finger carlo@runaway.xs4all.nl for public key (dialin, try at 21-22h GMT).
//

#ifndef SUPPORT_LOCKABLE_AUTO_PTR_H
#ifdef __GNUG__
#pragma interface
#endif
#define SUPPORT_LOCKABLE_AUTO_PTR_H

RCSTAG_H(support_lockable_auto_ptr, "$Id: lockable_auto_ptr.h,v 1.1 1998/11/24 15:08:15 carlo Exp $")

//=========================================================================
//
// class lockable_auto_ptr
//
// An 'auto_ptr' with lockable ownership.
//
// When the `lockable_auto_ptr' is not locked it behaves the same as
// an 'auto_ptr': Ownership of the object it points to is transfered
// when the `lockable_auto_ptr' is copied or assigned to another
// `lockable_auto_ptr'.  The object it points to is deleted when the
// `lockable_auto_ptr' that owns it is destructed.
//
// When the `lockable_auto_ptr' is locked, then the ownership is
// not transfered, but stays on the same (locked) `lockable_auto_ptr'.
//

template<class X>
class lockable_auto_ptr {
  typedef X element_type;

private:
  X* ptr;   // Pointer to object of type X, or NULL when not pointing to anything.
  bool locked;   // Set if this lockable_auto_ptr object is locked.
  mutable bool owner;  // Set if this lockable_auto_ptr object is the owner of the object that `ptr' points too.

public:
  //-----------------------------------------------------------------------
  // Constructors
  //

  explicit lockable_auto_ptr(X *p = 0) : ptr(p), locked(false), owner(p) {}
      // Explicit constructor that creates a lockable_auto_ptr pointing to `p'.

  lockable_auto_ptr(const lockable_auto_ptr &r) : ptr(r.ptr), locked(false), owner(r.owner && !r.locked) { if (!r.locked) r.owner = 0; }
      // The default copy constructor.

  template<class Y>
  lockable_auto_ptr(const lockable_auto_ptr<Y> &r) : ptr(r.ptr), locked(false), owner(r.owner && !r.locked) { if (!r.locked) r.owner = 0; }
      // Constructor to copy a lockable_auto_ptr that point to an object derived from X.

  //-----------------------------------------------------------------------
  // Operators
  //

  template<class Y> friend class lockable_auto_ptr<Y>;
  template<class Y>
  lockable_auto_ptr &operator=(const lockable_auto_ptr<Y> &r);

  lockable_auto_ptr &operator=(const lockable_auto_ptr &r) { return operator= <X> (r); }
      // The default assignment operator.

  //-----------------------------------------------------------------------
  // Destructor
  //

  ~lockable_auto_ptr() { if (owner) delete ptr; }

  //-----------------------------------------------------------------------
  // Accessors
  //

  X& operator*() const { return *ptr; }
    // Access the object that this `lockable_auto_ptr' points to.

  X* operator->() const { return ptr; }
    // Access the object that this `lockable_auto_ptr' points to.

  X* get() const { return ptr; }
    // Return the pointer itself.

  bool strict_owner() const { return locked; }
    // Returns `true' when this object is the strict owner.
    // You should only call this when this object is the owner.

#ifdef DEBUG
  bool is_owner(void) const { return owner; }
    // Don't use this except for debug testing.
#endif

  //-----------------------------------------------------------------------
  // Manipulators
  //

  void reset() { bool owns = owner; owner = 0; if (owns) delete ptr; ptr = NULL; }
    // Get rid of object, if any.

  X* release() const { ASSERT(is_owner()); owner = 0; return ptr; }
    // Release this object of its ownership (the caller is now responsible for deleting it if this object was the owner)
    // You should only call this when this object is the owner.

  void lock() { ASSERT(is_owner()); locked = true; }
    // Lock the ownership.
    // You should only call this when this object is the owner.

  void unlock() { locked = false; }
    // Unlock the ownership (if any).
};

template<class X>
template<class Y>
lockable_auto_ptr<X> &lockable_auto_ptr<X>::operator=(const lockable_auto_ptr<Y> &r)
{
  if ((void*)&r != (void*)this)
  {
    if (owner)
      delete ptr;
    ptr = r.ptr;
    owner = r.owner;
    r.owner = 0;
  }
  return *this;
}

#endif // SUPPORT_LOCKABLE_AUTO_PTR_H

--------------E9CC40392CB5E219A89BBC6A--
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: dHarrison@worldnet.att.net (Doug Harrison)
Date: 1999/01/04
Raw View
On 25 Jul 1998 00:29:28 GMT, abrahams@motu.com (David Abrahams) wrote:

>Now when it comes to mutable members, well, a mutable auto_ptr is a
>very common and useful way to implement a cache. I don't want the
>auto_ptr to be copied by default, transferring the cache from one
>containing object to another.

I'd suggest that if you don't want an object to be copied, use a class
that disallows copying. Given a smart pointer that doesn't support
copying at all, and a reference-counted smart pointer that supports it
properly, I find very little use for std::auto_ptr.

--
Doug Harrison
dHarrison@worldnet.att.net


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/05
Raw View
In article <6pg8gk$puo@bgtnsc02.worldnet.att.net>, Doug Harrison
<dHarrison@worldnet.att.net> writes
>I'd suggest that if you don't want an object to be copied, use a class
>that disallows copying. Given a smart pointer that doesn't support
>copying at all, and a reference-counted smart pointer that supports it
>properly, I find very little use for std::auto_ptr.

The problem with reference counted smart pointers is cycles.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/05
Raw View
On 5 Jan 1999 00:45:15 GMT, Francis Glassborow
>In article <6pg8gk$puo@bgtnsc02.worldnet.att.net>, Doug Harrison

>>I'd suggest that if you don't want an object to be copied, use a class
>>that disallows copying. Given a smart pointer that doesn't support
>>copying at all, and a reference-counted smart pointer that supports it
>>properly, I find very little use for std::auto_ptr.

The "auto_ptr" is good for use inside a function.  It prevents memory
leaks in the face of exceptions.  The "auto_ptr" is sometimes good
as a member of a class, but this is a less strong argument because
the class can have a destructor that properly releases memory.  In
this case, the "auto_ptr" is useful for preventing memory leaks in
the constructor.  And "auto_ptr" is sometimes good for return
value, although now we can't get covariant return types.


>The problem with reference counted smart pointers is cycles.

Too brief.  What do you mean?  Why does standard C++ not contain
a reference counting class?

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/06
Raw View
In article <slrn794pg7.86l.sbnaran@fermi.ceg.uiuc.edu>, Siemel Naran
<sbnaran@fermi.ceg.uiuc.edu> writes
>>The problem with reference counted smart pointers is cycles.
>
>Too brief.  What do you mean?  Why does standard C++ not contain
>a reference counting class?


This area is outside my area of expertise but I know there was a lot of
discussion about providing such a smart pointer which continually hit
the problem of 'how to break a cycle of objects' each containing a
reference to the next one.  I know there are techniques for dealing with
this problem but at the stage that it was under consideration no
concensus could be reached.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/01/06
Raw View
In article <slrn794pg7.86l.sbnaran@fermi.ceg.uiuc.edu>,
  sbnaran@KILL.uiuc.edu wrote:
> On 5 Jan 1999 00:45:15 GMT, Francis Glassborow
> >In article <6pg8gk$puo@bgtnsc02.worldnet.att.net>, Doug Harrison
>
> >>I'd suggest that if you don't want an object to be copied, use a class
> >>that disallows copying. Given a smart pointer that doesn't support
> >>copying at all, and a reference-counted smart pointer that supports it
> >>properly, I find very little use for std::auto_ptr.
>
> The "auto_ptr" is good for use inside a function.  It prevents memory
> leaks in the face of exceptions.  The "auto_ptr" is sometimes good
> as a member of a class, but this is a less strong argument because
> the class can have a destructor that properly releases memory.  In
> this case, the "auto_ptr" is useful for preventing memory leaks in
> the constructor.  And "auto_ptr" is sometimes good for return
> value, although now we can't get covariant return types.

In my experience, there are many cases where single ownership, with
transfer of ownership, is appropriate.  In all such cases, shared
ownership can also be used; in practice, because of the large number of
questions concerning auto_ptr, I've stuck with my reference counted
pointer until now.  Once all major vendors are close to the standard,
however, I'll probably switch to auto_ptr for this.

> >The problem with reference counted smart pointers is cycles.
>
> Too brief.  What do you mean?  Why does standard C++ not contain
> a reference counting class?

There are two separate questions.

The problem with reference counted pointers occurs when they are used
systematically, object A contains a pointer to B and object B a pointer
to A.  The solution is to analyse your relationships, and use proper
relationship management classes.

I don't really know the reason why reference counted pointers are not in
the standard, but I do know that they were discussed.  I suspect that
part of the reason might be that there are two different possible
implementations, and that no concensus could be found for either.  (You
can use invasive reference counting, as described in Scott Meyers, but
then you can't have reference counted pointers to built-in types, or to
libraries that you didn't write.  Or you can use non-invasive reference
counting, as described in Barton and Nackman, but then you have
significantly more overhead, and a reference counted pointer no longer
fits in a register.)

--
James Kanze                                           GABI Software, S   rl
Conseils en informatique orient    objet  --
                          --  Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr          mailto: James.Kanze@dresdner-bank.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1999/01/07
Raw View
In article <9p6KmpA$uqk2EwkR@robinton.demon.co.uk>,
  Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
>
> In article <slrn794pg7.86l.sbnaran@fermi.ceg.uiuc.edu>, Siemel Naran
> <sbnaran@fermi.ceg.uiuc.edu> writes
> >>The problem with reference counted smart pointers is cycles.
> >
> >Too brief.  What do you mean?  Why does standard C++ not contain
> >a reference counting class?
>
> This area is outside my area of expertise but I know there was a lot of
> discussion about providing such a smart pointer which continually hit
> the problem of 'how to break a cycle of objects' each containing a
> reference to the next one.  I know there are techniques for dealing with
> this problem but at the stage that it was under consideration no
> concensus could be reached.

Public documentation for "Great Circle" GC documents their solution.
When hunting for inaccessable blocks, they begin with everything on
the stack that looks like a pointer, and flag the pointed-to block
as being in use. Then they search every block for more pointers. If
there are two blocks that point to each other, but nothing else points
to either one of them, the algorithm won't find any pointers, and so
will consider the blocks to be discardable.

Such a scheme SOUNDS as if it would take a long time, but the GC
documentation says otherwise, and I have no experience one way or
the other.

--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Marc-Andri lafortune <lafortne@math.Princeton.EDU>
Date: 1998/07/24
Raw View
As far as I can understand, according to section 12.8 (of the only
freely available draft-standard ('96?)), the default constructor for a
class B will have the semantics:

B(const B &)

only if all its members have such semantics. It seems to me that if a
class A has the 'auto_ptr semantics'   A(A &), and that B has a
_mutable_ member A, then the copy semantics should be B(const B&), not
B(B&). Did that change in the latests standard, and if not, can someone
tell me why?

If what I said is not too clear, here's a code example:

struct A {
 A(int i=0) : non_sharable(i) {}

// Note: unusual semantics: uses 'A &' instead of 'const A &'
 A(A &x)  { *this = x; }
 A &operator=(A &x) {
  non_sharable = x.non_sharable;
  x.non_sharable = 0; return *this;
 }

 int non_sharable;
};

struct B {
 mutable A internal_cache;
 B()      {}

// The following 3 lines don't do anything special.
// Are they still necessary according to the last standard?

// B(const B &x) : internal_cache(x.internal_cache) {}
// B &operator =(const B &x) { internal_cache = x.internal_cache;
//   return *this; }

};

void
main() {
 const B b;
 B c(b);
 B d; d = b;
}

Thanks.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1998/07/24
Raw View
Marc-Andri lafortune <lafortne@math.Princeton.EDU> writes:

>As far as I can understand, according to section 12.8 (of the only
>freely available draft-standard ('96?)), the default constructor for a
>class B will have the semantics:
>
>B(const B &)
>
>only if all its members have such semantics. It seems to me that if a
>class A has the 'auto_ptr semantics'   A(A &), and that B has a
>_mutable_ member A, then the copy semantics should be B(const B&), not
>B(B&). Did that change in the latests standard,

No.

>and if not, can someone tell me why?

As far as I know, no-one raised this issue.

I think your suggestion is a good one -- in 12.8/5, the wording
"for all the nonstatic data members of X" should instead
be "for all the nonstatic nonmutable data members of X".
                          ^^^^^^^^^^

However, since the standard has just been voted on,
any changes will have to wait until the standard
is amended or revised.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: abrahams@motu.com (David Abrahams)
Date: 1998/07/25
Raw View
On 24 Jul 98 07:51:53 GMT, fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:

>Marc-Andri lafortune <lafortne@math.Princeton.EDU> writes:
>
>>As far as I can understand, according to section 12.8 (of the only
>>freely available draft-standard ('96?)), the default constructor for a
>>class B will have the semantics:
>>
>>B(const B &)
>>
>>only if all its members have such semantics. It seems to me that if a
>>class A has the 'auto_ptr semantics'   A(A &), and that B has a
>>_mutable_ member A, then the copy semantics should be B(const B&), not
>>B(B&). Did that change in the latests standard,
>
>No.
>
>>and if not, can someone tell me why?
>
>As far as I know, no-one raised this issue.
>
>I think your suggestion is a good one -- in 12.8/5, the wording
>"for all the nonstatic data members of X" should instead
>be "for all the nonstatic nonmutable data members of X".
>                          ^^^^^^^^^^

I have mixed feelings about this. First of all, I hadn't realized that
an implicitly declared copy constructor is produced when the rhs is
non-const. That seems rather dangerous. The only place I've ever seen
a need for a non-const rhs in a copy constructor was in auto_ptr, and
I think we can all agree that it would be safer if classes with
auto_ptr members didn't get a copy constructor by default. Any class
with a non-const rhs in its copy constructor is likely to impose the
same kind of unintended semantics on its containing class.
Unfortunately, we're probably stuck with this for a while at least,
since it's enshrined in the standard.

Now when it comes to mutable members, well, a mutable auto_ptr is a
very common and useful way to implement a cache. I don't want the
auto_ptr to be copied by default, transferring the cache from one
containing object to another. Although your suggestion is clearly more
consistent with the existing intent of the standard, I'd rather not
liberalize the generation of implicit copy constructors any more than
it already is. In fact, I'd prefer to deprecate the non-const rhs
case.

Does anyone know why these semantics were included? Perhaps there's
some important reason which I've overlooked...

-Dave


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]