Topic: auto_ptr in standard containers


Author: hsutter@peerdirect.com (Herb Sutter)
Date: 1999/09/19
Raw View
On 7 Sep 1999 15:33:14 GMT, Kevin Kostrzewa <tkkost@newsguy.com> wrote:
>I'm curious - does anybody know if the standards committe contemplated
>establishing something in auto_ptr to make it so that creating a
>container of auto_ptr<T> objects would *not* compile?

Yes. The final auto_ptr design was deliberately specified in such a way
that a natural implementation of the standard library's containers would
fail to compile if instantiated with auto_ptrs. (It's still possible to
implement the standard containers in a way that will not fail to compile
with auto_ptrs, but natural implementations will.)

Herb

---
Herb Sutter (mailto:hsutter@peerdirect.com)

PeerDirect Inc.     2695 North Sheridan Way, Suite 150
www.peerdirect.com  Mississauga Ontario Canada L5K 2N6


[ 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@uiuc.edu (Siemel B. Naran)
Date: 1999/09/07
Raw View
On 7 Sep 1999 15:33:14 GMT, Kevin Kostrzewa <tkkost@newsguy.com> wrote:
>Francis Glassborow <francis@robinton.demon.co.uk> writes:

>> Let me assure you that without a killer example the intense technical
>> work done at the last minute to make auto_ptr have safer behaviour would
>> not have happened.

But if one does not use algorithms, then a container of auto_ptr should be
safe.  Yet the standard still doesn't allow it.


>I'm curious - does anybody know if the standards committe contemplated
>establishing something in auto_ptr to make it so that creating a
>container of auto_ptr<T> objects would *not* compile?

Yes.  The function std::allocator<T>::construct, which the container
uses to construct objects.  The container's copy constructor,
push_back, push_front, etc all use this construct function.  It is

   template <class T>
   void std::allocator<T>::construct(T * place, const T& object) {
      new (place) T(object);
   }

We see that it uses T::T(const T&).  So T==std::auto_ptr<U> does
not qualify because it only has T::T(T&).


My first two suggestions to the original poster were to just use
raw pointers and remember to delete the pointer to objects -- a
good choice if your container is a private member of a useful
class --, and to write a class counted_ptr<T> and make a container
of counted_ptr<> objects.

My third suggestion was to write a new allocator object that
would permit a container of auto_ptr objects.  I'm not sure if
this is a good suggestion.  I got a feeling it isn't.  Here is
what I've come up with, but it doesn't do what I expect on egcs.
This could be because the /usr/include/g++/vector is bizarre.

Do you have any comments or criticism?



#include <cstddef>
#include <cstdlib>


template <class T>
class delete_allocator
{
   public:
      typedef size_t      size_type;
      typedef ptrdiff_t   difference_type;
      typedef T           value_type;

      template <class U> struct rebind { typedef delete_allocator<U> other; };

      delete_allocator() {}
      template <class U> delete_allocator(const delete_allocator<U>&) {}
      ~delete_allocator() {}


      value_type * allocate(size_type n)
      {
         return static_cast<value_type *>(malloc(n*sizeof(value_type)));
      }

      void deallocate(value_type * p, size_type /*n*/)
      {
         free(p);
      }

      size_type max_size() const
      {
         return size_type(-1) / size_type(sizeof(value_type));
      }

      void construct(value_type * place, const value_type& orig)
      {
         new (place) value_type(orig);
         *orig=0;
      }

      void destroy(value_type * place) { delete *place; }
};

/////
/////
/////

#include <iostream.h>
#include <vector>

struct Thing
{
   int i;
   explicit Thing(int i) : i(i) { cout << "Thing " << i << endl; }
   Thing(const Thing& o) : i(o.i) { cout << "Thing@ " << i << endl; }
   void operator=(const Thing& o) { i=o.i; cout << "Thing= " << i << endl; }
   ~Thing() { cout << "~Thing " << i << endl; }
};

int main()
{
   std::vector<Thing*,delete_allocator<Thing*> > c;
   for (int i=0; i<20; i++) c.push_back(new Thing(i));
}


--
--------------
siemel b naran
--------------


[ 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/09/07
Raw View
In article <wk4sh6ubm3.fsf@newsguy.com>, Kevin Kostrzewa
<tkkost@newsguy.com> writes
>I'm curious - does anybody know if the standards committe contemplated
>establishing something in auto_ptr to make it so that creating a
>container of auto_ptr<T> objects would *not* compile?

Well as you are allowed empty containers I find it hard to imagine what
that might be.


Francis Glassborow      Journal Editor, 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/02
Raw View
In article <slrn7sqqqh.tua.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>Can you give me some examples of the potential problems that compilers
>might miss?

It seems to me that we have been round this an awful lot of times.
auto_ptr is not copyconstructable within the terms of the standard.
None-the-less the CD2 version allowed compilers to accept containers of
auto_ptr even though they could/would exhibit undefined behaviour
(remember that a feature of undefined behaviour is that the compiler is
not required to issue a diagnostic, indeed it may not be able to do so.)



Francis Glassborow      Journal Editor, 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: Kevin Kostrzewa <tkkost@newsguy.com>
Date: 1999/09/07
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
[snip]
> I know
> that it was something along those lines that persuaded a number of
> people that their claim that they had never had a problem with
> containers of auto_ptr was their good fortune.  The worst conceivable
> kind of breakage is one that happens rarely because those unaware of the
> problem blithely continue along their current path.
>
> Let me assure you that without a killer example the intense technical
> work done at the last minute to make auto_ptr have safer behaviour would
> not have happened.

I'm curious - does anybody know if the standards committe contemplated
establishing something in auto_ptr to make it so that creating a
container of auto_ptr<T> objects would *not* compile?

--
kevin kostrzewa
work: kkostrzewa@csisolutions.com
home: tkkost@newsguy.com


[ 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@uiuc.edu (Siemel B. Naran)
Date: 1999/09/02
Raw View
On 01 Sep 99 17:06:17 GMT, Francis Glassborow

>The semantics of auto_ptr are wrong and have always been wrong for
>containers (containers require copy ctors and assignment to work without
>changing the original, auto_ptr versions transfer ownership).  Until
>recently the definition of auto_ptr was such that the compiler was
>likely to miss the potential problems and just give you undefined
>behaviour out of the blue.  The final version was carefully honed to
>greatly increase the chance of early detection of abuse.

Can you give me some examples of the potential problems that compilers
might miss?

--
--------------
siemel b naran
--------------


[ 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: hsutter@peerdirect.com (Herb Sutter)
Date: 1999/09/03
Raw View
On 31 Aug 1999 15:01:58 GMT, Gordon Watts <gwatts@fnal.gov> wrote:
>  Yes, I know. I did do a search of deja before I started here and while
>there was a lot of discussion on the use of auto_ptr, there wasn't much on
>the use of it in a container other than... don't!

In addition to the other replies, you might want to see my article on
auto_ptr in the October 1999 C/C++ Users Journal. I think it answers
most of your questions, and it should hit the shelves soon.

Herb

---
Herb Sutter (mailto:hsutter@peerdirect.com)

PeerDirect Inc.     2695 North Sheridan Way, Suite 150
www.peerdirect.com  Mississauga Ontario Canada L5K 2N6


[ 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@uiuc.edu (Siemel B. Naran)
Date: 1999/09/03
Raw View
On 2 Sep 1999 22:26:04 GMT, Francis Glassborow

>>Can you give me some examples of the potential problems that compilers
>>might miss?

>It seems to me that we have been round this an awful lot of times.
>auto_ptr is not copyconstructable within the terms of the standard.
>None-the-less the CD2 version allowed compilers to accept containers of
>auto_ptr even though they could/would exhibit undefined behaviour
>(remember that a feature of undefined behaviour is that the compiler is
>not required to issue a diagnostic, indeed it may not be able to do so.)

Yes, we've been through this.  But I never once got a specific example
of what might go wrong.

--
--------------
siemel b naran
--------------


[ 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/09/03
Raw View
In article <slrn7suhj7.j0f.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>Yes, we've been through this.  But I never once got a specific example
>of what might go wrong.

IIRC one problem is that certain sort algorithms use pivot elements that
are copied.  If they are not copied back to the container the container
loses ownership of the object being pointed to by the auto_ptr.  I know
that it was something along those lines that persuaded a number of
people that their claim that they had never had a problem with
containers of auto_ptr was their good fortune.  The worst conceivable
kind of breakage is one that happens rarely because those unaware of the
problem blithely continue along their current path.

Let me assure you that without a killer example the intense technical
work done at the last minute to make auto_ptr have safer behaviour would
not have happened.


Francis Glassborow      Journal Editor, 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 Kuyper <kuyper@wizard.net>
Date: 1999/09/01
Raw View
Gordon Watts wrote:
...
>   If I can't use auto_ptr's in a container, what is the best way to make
> sure that the list of pointers I'm holding is deleted? Do I have to go back
> to writing a extra loop that walks the container deleting everything in it
> one at a time before the container is deleted? The auto_ptr method just
> seemed so much nicer. :(

Make a container of smart pointers. Make sure that your smart pointer
class is, among other things, CopyConstructible, as defined in the
standard.
---
[ 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/09/01
Raw View
In article <7qfcfu$h95$1@info3.fnal.gov>, Gordon Watts <gwatts@fnal.gov>
writes
>  If I can't use auto_ptr's in a container, what is the best way to make
>sure that the list of pointers I'm holding is deleted? Do I have to go back
>to writing a extra loop that walks the container deleting everything in it
>one at a time before the container is deleted? The auto_ptr method just
>seemed so much nicer. :(

The semantics of auto_ptr are wrong and have always been wrong for
containers (containers require copy ctors and assignment to work without
changing the original, auto_ptr versions transfer ownership).  Until
recently the definition of auto_ptr was such that the compiler was
likely to miss the potential problems and just give you undefined
behaviour out of the blue.  The final version was carefully honed to
greatly increase the chance of early detection of abuse.

You need to find one of the implementations of a counted pointer.

Francis Glassborow      Journal Editor, 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: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/09/01
Raw View
Gordon Watts wrote in message <7qfcfu$h95$1@info3.fnal.gov>...
>  If I can't use auto_ptr's in a container, what is the best way to make
>sure that the list of pointers I'm holding is deleted?

The usual answer is to use smart pointers for reference counting.  This is
not part of the standard (see the FAQ at
http://reality.sgi.com/austern_mti/std-c++/faq.html#C3).  A non-intrusive
implementation is documented at
http://www.boost.org/libs/smart_ptr/shared_ptr.htm
Meyers gives an intrusive (base class) implementation at
http://cseng.aw.com/bookdetail.qry?ISBN=0-201-63371-X&ptype=0

I haven't used either of these so YMMV.
---
[ 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@uiuc.edu (Siemel B. Naran)
Date: 1999/09/01
Raw View
On 31 Aug 1999 15:01:58 GMT, Gordon Watts <gwatts@fnal.gov> wrote:

>  Yes, I know. I did do a search of deja before I started here and while
>there was a lot of discussion on the use of auto_ptr, there wasn't much on
>the use of it in a container other than... don't!

The standard containers use std::allocator<T>::construct to copy objects
from the outside world into the container.  Here is that function:

   std::allocator<T>::construct(T * place, const T& obj) {
      new (place) T(obj);
   }

As you can see, the default allocator requires the existence of
T::T(const T&).  An object with a copy constructor T::T(T&) doesn't
work.  Hence we can't use T==std::auto_ptr<U> objects inside the
container.


Objects with copy constructors T::T(T&) make exception safe container
functions (eg, push_back, copy constructor) hard to implement.
Suppose we start with a container std::vector<T> c={t1,t2,t3}.  Now
we copy this container with cc=c.

As the copy constructor of class T modifies its argument, we expect
c to become {t1',t2',t3'} and cc to become {t1,t2,t3}.  If during the
copy there is an exception, we expect c to be in its original state
{t1,t2,t3} -- this is what we mean by exception safety.  However, if
the exception comes after we copy t1, c will be in the state
{t1',t2,t3}, which goes against exception safety.


Though std::auto_ptr<T>::auto_ptr(auto_ptr&) does not throw, we
still have other problems:

   struct Silly {
      std::auto_ptr<int> operator()(std::auto_ptr<int>& i) const {
         if (*i==3) throw "hello world";
         return i;
      }
   };

   std::transform(in.begin(),in.end(),std::back_inserter(out),Silly());

There's a risk that 'in' will be in an inconsistent state, some
elements nullified and other elements untouched.  On the other hand,
maybe we don't care.




>  If I can't use auto_ptr's in a container, what is the best way to make
>sure that the list of pointers I'm holding is deleted? Do I have to go back
>to writing a extra loop that walks the container deleting everything in it
>one at a time before the container is deleted? The auto_ptr method just
>seemed so much nicer. :(


If your container is a private member of a class, then write this loop.
For example, class Account may contain a std::deque<Transaction*>.  Then
Account::~Account() deletes all the pointed to objects.


You may write a reference counting class, counted_ptr.  Then make a
std::deque<counted_ptr<Transaction>>.  The reference counting
mechanism takes care of deleting the pointed to objects.  In addition,
you get to make fast shallow copies (ie, pointer copies) of
transactions, but then you can change one transaction and the other
won't change.

The catch: the standard doesn't come with a counted_ptr class, so
you'll have to write your own.


A third option is to write your own allocator whose allocator uses
"T&" rather than "const T&", and then make a container using this
allocator.

--
--------------
siemel b naran
--------------
---
[ 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: Gordon Watts <gwatts@fnal.gov>
Date: 1999/08/31
Raw View
Hi,
  Yes, I know. I did do a search of deja before I started here and while
there was a lot of discussion on the use of auto_ptr, there wasn't much on
the use of it in a container other than... don't!

  I've gotten very used to using auto_ptr -- I was using with a compiler
that had the CD2 version (the one with a const copy constructor). My code
has to be cross platform, and work under KCC, and the recent versions don't
like it anymore.

  I use auto_ptr's all over my code -- mostly to make sure that delete gets
called in the when an exception occurs. I also use them in containers so
that when I'm holding onto a list of pointers (that I own), I'm sure they
will get deleted when the container is deleted. A very nice feature.

  If I can't use auto_ptr's in a container, what is the best way to make
sure that the list of pointers I'm holding is deleted? Do I have to go back
to writing a extra loop that walks the container deleting everything in it
one at a time before the container is deleted? The auto_ptr method just
seemed so much nicer. :(

    Cheers,
        Gordon.




[ 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              ]