Topic: Guru of the Week #25: Solution


Author: Ryszard Kabatek <kabatek@chemie.uni-halle.de>
Date: 1997/11/25
Raw View
Bill Wade wrote:
>
> Many operations with
>   vector< auto_ptr<T> > v;
> should fail because of no suitable copy constructor or operator=.  However
> if nothing is done with v (except for implicit destruction) is a diagnostic
> required?
>

Perhaps is it possible to make a specialisation for
vector<auto_ptr<T> > to skip the above difficulties?

--
Ryszard Kabatek     ,,,
                   (o o)
---------------o00--(_)--00o---------------
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/11/25
Raw View
Ryszard Kabatek wrote:
>
> Bill Wade wrote:
> >
> > Many operations with
> >   vector< auto_ptr<T> > v;
> > should fail because of no suitable copy constructor or operator=.  However
> > if nothing is done with v (except for implicit destruction) is a diagnostic
> > required?
> >
>
> Perhaps is it possible to make a specialisation for
> vector<auto_ptr<T> > to skip the above difficulties?

Like :

template <class T, class Alloc>
class vector<auto_ptr<T>, Alloc>;

or even

template <class T, class Alloc>
class vector<auto_ptr<T>, Alloc>
{
    Sorry, it doesn't work
};

But it will fail to compile with a modern compiler even
if the template isn't instantiated.

But the following shouldn't fail before instantiation:

template <class T, class Alloc>
class vector<auto_ptr<T>, Alloc>
{
    ~vector () { sorry_it_doesnt_work<T> (); }
};

because sorry_it_doesnt_work is dependant.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/11/26
Raw View
Ryszard Kabatek <kabatek@chemie.uni-halle.de> writes:

>Bill Wade wrote:
>>
>> Many operations with
>>   vector< auto_ptr<T> > v;
>> should fail because of no suitable copy constructor or operator=.  However
>> if nothing is done with v (except for implicit destruction) is a diagnostic
>> required?

No.  Diagnostics are never required for instantiating a template in the
standard library with a parameter that doesn't meet the requirements.
See 17.3.3.6 [lib.res.on.functions] paragraph 2.

>Perhaps is it possible to make a specialisation for
>vector<auto_ptr<T> > to skip the above difficulties?

No.  If you do that, then 17.3.3.1 [lib.reserved.names] paragraph 1 says
the behaviour is undefined.

--
Fergus Henderson <fjh@cs.mu.oz.au>   WWW: <http://www.cs.mu.oz.au/~fjh>
Note: due to some buggy software and a (probably accidental)
denial-of-service attack, any mail sent to me between
 Tue Nov 25 20:00:00 UTC (6am Wed, local time)
and Wed Nov 26 06:00:00 UTC (4pm, local time)
may have gone into the bit-bucket.  Please re-send it.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/11/21
Raw View
Herb Sutter <herbs@cntc.com> wrote in article
<34729ccf.1880942111@nr1.toronto.istar.net>...
> In summary:
>
> 1. All legitimate uses of auto_ptr work as before,
>    except that you can't use (i.e., dereference) a
>    non-owning auto_ptr.
>
> 2. The dangerous abuses of auto_ptr have been made
>    illegal.

Hurrah!

Is it safe to say that auto_ptr is back to the April '95 draft version
(with some additions and clarifications such as explicit construction from
T*  and operator=() usually calls delete)?  Is reset() reborn?

I believe the primary motivation for the changes from 4/95 to 12/96 was to
allow an auto_ptr to be used as the return value from a function.  In the
4/95 version this was almost useless because the return value from a
function is a temporary and temporaries can't be used as non-const
arguments.  What has been done to get around this problem (Herb's posting
shows examples of functions returning an auto_ptr)?

I think this means:

1) Copy construction and assignment take non-const RHS only.  No need for
mutable member(s).
2) No need for "ownership-bit".  Ownership is equivalent to non-zero get().
 That
means there is almost no performance penalty (in principle) compared to
dumb pointers.

Some questions (for those of us who won't see the real standard for a
while).

Is
  auto_ptr<Base> a(auto_ptr<Derived>);
supported?  How about the corresponding assignment? I'd expect that Base
and Derived mean "Derived* can be implicitly converted to Base*", not
necessarily that there is an inheritance relationship.

Does operator=() return (non-const) *this?

Many operations with
  vector< auto_ptr<T> > v;
should fail because of no suitable copy constructor or operator=.  However
if nothing is done with v (except for implicit destruction) is a diagnostic
required?

Similar to the previous paragraph:
void Test(){
  vector<auto_ptr<T> > v(10);
  v[3] = SomeAppropriateAutoPtr();
  v[3]->DoSomeTthing();
}
Is this portable?  Is a diagnostic required?

Given

  auto_ptr<T> a;
  T* t = something_else();

Is there a way to achieve

  a = t;  // Assignment, not construction

as a one-liner?  Some attempts:

  a = t; // Oops: No assignment taking T*, and construction must be
explicit.
  a = auto_ptr<T>(t);  // Oops: Temporary used as non-const argument to
op=()
  delete a.reset(t); // Oops: Was in the 4/95 draft, dropped in 12/96
draft.
     // In Meyer, More Effective C++ reset() is void, so remove
     // the delete.

Thanks in advance for incinerating any of my misconceptions ;-)
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/11/21
Raw View
Bill Wade wrote:
>
> Herb Sutter <herbs@cntc.com> wrote in article
> <34729ccf.1880942111@nr1.toronto.istar.net>...
> > In summary:
> >
> > 1. All legitimate uses of auto_ptr work as before,
> >    except that you can't use (i.e., dereference) a
> >    non-owning auto_ptr.
> >
> > 2. The dangerous abuses of auto_ptr have been made
> >    illegal.
>
> Hurrah!

Indeed.

> Is it safe to say that auto_ptr is back to the April '95 draft version
> (with some additions and clarifications such as explicit construction from
> T*  and operator=() usually calls delete)?

No, putting back the April auto_ptr isn't a solution (otherwise we
would have kept it).

> Is reset() reborn?

Yes

> I believe the primary motivation for the changes from 4/95 to 12/96 was to
> allow an auto_ptr to be used as the return value from a function.  In the
> 4/95 version this was almost useless because the return value from a
> function is a temporary and temporaries can't be used as non-const
> arguments.

With this auto_ptr, you could write:

  auto_ptr<int> foo ();
  auto_ptr<int> p (foo ().release ());

> What has been done to get around this problem (Herb's posting
> shows examples of functions returning an auto_ptr)?

Converting ctors/convertion operators/intermediate class tricks.

> I think this means:
>
> 1) Copy construction and assignment take non-const RHS only.  No need for
> mutable member(s).
> 2) No need for "ownership-bit".  Ownership is equivalent to non-zero get().
>  That
> means there is almost no performance penalty (in principle) compared to
> dumb pointers.

Correct. The mutable bit wasn't very clean.

> Is
>   auto_ptr<Base> a(auto_ptr<Derived>);
> supported?  How about the corresponding assignment? I'd expect that Base
> and Derived mean "Derived* can be implicitly converted to Base*", not
> necessarily that there is an inheritance relationship.

The only way to implicitly convert from Der* to Base* is to
have Der derived from Base.

> Does operator=() return (non-const) *this?

I think so.

> Many operations with
>   vector< auto_ptr<T> > v;
> should fail because of no suitable copy constructor or operator=.  However
> if nothing is done with v (except for implicit destruction) is a diagnostic
> required?

I don't think so, but it would be difficult to write a vector<>
which allows anything without diagnostics.

> Similar to the previous paragraph:
> void Test(){
>   vector<auto_ptr<T> > v(10);
>   v[3] = SomeAppropriateAutoPtr();
>   v[3]->DoSomeTthing();
> }
> Is this portable?  Is a diagnostic required?

auto_ptr<T> doesn't satisfy CopyContructible, so
vector< auto_ptr<T> > isn't garantied to work.

And most operations will fail to compile (the ones
above will probably work).

> Given
>
>   auto_ptr<T> a;
>   T* t = something_else();
>
> Is there a way to achieve
>
>   a = t;  // Assignment, not construction

>   delete a.reset(t); // Oops: Was in the 4/95 draft, dropped in 12/96
> draft.

reset is back, and delete its object

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: herbs@cntc.com (Herb Sutter)
Date: 1997/11/18
Raw View
[Cross-posted to comp.std.c++ because of the standards-
related content.]

[Note: Apparently the GotW #25 question didn't get
widely propagated... I never saw it at my news server,
and DejaNews didn't get it either.  Since I know some
people did get it, I'll just post the answer anyway.]


 .--------------------------------------------------------------------.
 |  Guru of the Week problems and solutions are posted regularly on   |
 |   news:comp.lang.c++.moderated. For past problems and solutions    |
 |            see the GotW archive at http://www.cntc.com.            |
 | Is there a topic you'd like to see covered? mailto:herbs@cntc.com  |
 `--------------------------------------------------------------------'

GotW #25:   auto_ptr        (Special Edition)

Difficulty: 8 / 10


>Comment on the following code:  What's good, what's
>safe, what's legal, and what's not?

*******************************************************
STANDARDS UPDATE:  This week, at the WG21/J16 meeting
in Morristown NJ USA, the Final Draft International
Standard (FDIS) for Programming Language C++ was voted
out for balloting by national bodies.  We expect to
know by the next meeting (Nice, March 1998) whether it
has passed and will become an official ISO Standard.
*******************************************************

This GotW was posted knowing that auto_ptr was going to
be refined at the New Jersey meeting in order to
satisfy national body comments.  This Special Edition
of GotW covers the final auto_ptr, how and why been
made safer and easier to use, and how to use it best.

In summary:

1. All legitimate uses of auto_ptr work as before,
   except that you can't use (i.e., dereference) a
   non-owning auto_ptr.

2. The dangerous abuses of auto_ptr have been made
   illegal.

SOME WELL-DESERVED ACKNOWLEDGMENTS:  Many thanks from
all of us to Bill Gibbons, Greg Colvin, Steve Rumsby,
and others who worked hard on the final refinement of
auto_ptr.  Greg in particular has laboured over
auto_ptr and related classes for many years to satisfy
various committee concerns and requirements, and
deserves public recognition for that work.


Background
----------

The original motivation for auto_ptr was to make code
like the following safer:

    void f() {
        T* pt( new T );
        /*...more code...*/
        delete pt;
    }

If f() never executes the delete statement (either
because of an early return or by an exception thrown in
the function body), the allocated object is not deleted
and we have a classic memory leak.

A simple way to make this safe is to wrap the pointer
in a "smarter" pointer-like object which owns the
pointer and which, when destroyed, deletes the pointer
automatically:

    void f() {
        auto_ptr<T> pt( new T );
        /*...more code...*/
    } // cool: pt's dtor is called as it goes out of
      // scope, and the allocated object is deleted

Now the code will not leak the T object, no matter
whether the function exits normally or by means of an
exception, because pt's destructor will always be
called during stack unwinding.  Similarly, auto_ptr can
be used to safely wrap pointer data members:

    // file c.h
    class C {
    public:
        C();
        /*...*/
    private:
        auto_ptr<CImpl> pimpl_;
    };

    // file c.cpp
    C::C() : pimpl_( new CImpl ) { }

Now the destructor need not delete the pimpl_ pointer,
since the auto_ptr will handle it automatically.  We'll
revisit this example again at the end.


Sources and Sinks
-----------------

This is cool stuff all by itself, but it gets better.
Based on Greg Colvin's work and experience at Taligent,
people noticed that if you defined copying for
auto_ptrs then it would be very useful to pass them to
and from functions, as function parameters and return
values.

This is in fact the way auto_ptr worked in the second
committee draft (Dec 1996), with the semantics that the
act of copying an auto_ptr transfers ownership from the
source to the target.  After the copy, only the target
auto_ptr "owned" the pointer and would delete it in due
time, while the source also still contained the same
pointer but did not "own" it and therefore would not
delete it (else we'd have a double delete).  You could
still use the pointer through either an owning or a
non-owning auto_ptr object.

For example:

    void f() {
        auto_ptr<T> pt1( new T );
        auto_ptr<T> pt2;

        pt2 = pt1;  // now pt2 owns the pointer, and
                    // pt1 does not

        pt1->DoSomething(); // ok (before last week)
        pt2->DoSomething(); // ok

    } // as we go out of scope, pt2's dtor deletes the
      // pointer, but pt1's does nothing

This gets us to the first part of the GotW code: [1]

>    auto_ptr<T> source() {
>        return auto_ptr<T>( new T(1) );
>    }
>    void sink( auto_ptr<T> pt ) { }

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes         Yes
  | Safe?      Yes         Yes

This demonstrates exactly what the people at Taligent
had in mind:

1. source() allocates a new object and returns it to
   the caller in a completely safe way, by letting the
   caller assume ownership of the pointer.  Even if the
   caller ignores the return value (of course, you
   would never write code that ignores return values,
   right?), the allocated object will always be safely
   deleted.

   See also GotW #21, which demonstrates why this is an
   important idiom, since returning a result by
   wrapping it in an auto_ptr is sometimes the only way
   to make a function strongly exception-safe.

2. sink() takes an auto_ptr by value and therefore
   assumes ownership of it.  When sink() is done, the
   deletion is done (as long as sink() itself hasn't
   handed off ownership to someone else).  Since the
   sink() function as written above doesn't do anything
   with the body, calling "sink( a );" is a fancy way
   of writing "a.release();".

The next piece of code shows source() and sink() in
action:

>    void f() {
>        auto_ptr<T> a( source() );

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes         Yes
  | Safe?      Yes         Yes

Here f() takes ownership of the pointer received from
source(), and (ignoring some problems later in f()) it
will delete it automatically when the automatic
variable a goes out of scope.  This is fine, and it's
exactly how passing back an auto_ptr by value is
meant to work.

>        sink( source() );

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes         Yes
  | Safe?      Yes         Yes

Given the trivial (i.e., empty) definitions of source()
and sink() here, this is just a fancy way of writing
"delete new T(1);".  So is it really useful?  Well, if
you imagine source() as a nontrivial factory function
and sink() as a nontrivial consumer, then yes, it makes
a lot of sense and crops up regularly in real-world
programming.

>        sink( auto_ptr<T>( new T(1) ) );

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes         Yes
  | Safe?      Yes         Yes

Again, a fancy way of writing "delete new T(1);", and a
useful idiom when sink() is a nontrivial consumer
function that takes ownership of the pointed-to object.


Things Not To Do, and Why Not To Do Them
----------------------------------------

"So," you say, "that's cool, and obviously supporting
auto_ptr copying is a Good Thing."  Well, yes, it is,
but it turns out that it can also get you into hot
water where you least expect it, and that's why the
national body comments objected to leaving auto_ptr in
the CD2 form.  Here's the fundamental issue, and I'll
highlight it to make sure it stands out:

    *** For auto_ptr, copies are NOT equivalent.

It turns out that this has important effects when you
try to use auto_ptr with generic code that does make
copies and isn't necessarily aware that copies aren't
equivalent (after all, usually copies are!).  Consider:

>        vector< auto_ptr<T> > v;

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes          No
  | Safe?       No          No

This is the first indication of trouble, and one of the
things the national body comments wanted fixed.  In
short, even though a compiler wouldn't burp a single
warning here, auto_ptrs are NOT safe to put in
containers.  This is because we have no way of warning
the container that copying auto_ptrs has unusual
semantics (transferring ownership, changing the
right-hand side's state).  True, today most
implementations I know about will let you get away with
this, and code nearly identical to this even appears as
a "good example" in the documentation of certain
popular compilers.  Nevertheless, it was actually
unsafe (and is now illegal).

The problem is that auto_ptr does not quite meet the
requirements of a type you can put into containers, for
copies of auto_ptrs are not equivalent.  For one thing,
there's nothing that says a vector can't just decide to
up and make an "extra" internal copy of some object it
contains.  Sure, normally you can expect vector not to
do this (simply because making extra copies happens to
be unnecessary and inefficient, and for competitive
reasons a vendor is unlikely to ship a library that's
needlessly inefficient), but it's not guaranteed and so
you can't rely on it.

But hold on, because it's about to get worse:

>        v.push_back( auto_ptr<T>( new T(3) ) );
>        v.push_back( auto_ptr<T>( new T(4) ) );
>        v.push_back( auto_ptr<T>( new T(1) ) );
>        v.push_back( a );

(Aside:  Note that copying a into the vector means that
the 'a' object no longer owns the pointer it's
carrying.  More on that in a moment.)

>        v.push_back( auto_ptr<T>( new T(2) ) );
>        sort( v.begin(), v.end() );

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes          No
  | Safe?       No          No

Here's the real devil, and another reason why the
national body comment was more that just a suggestion
(the body in question actually voted No on CD2 largely
because of this problem).  When you call generic
functions that will copy elements, like sort() does,
the functions have to be able to assume that copies are
going to be equivalent.  For example, at least one
popular sort internally takes a copy of a "pivot"
element, and if you try to make it work on auto_ptrs it
will merrily take a copy of the pivot auto_ptr object
(thereby taking ownership and putting it in a temporary
auto_ptr on the side), do the rest of their work on the
sequence (including taking further copies of the
now-non-owning auto_ptr that was picked as a pivot
value), and when the sort is over the pivot is
destroyed and you have a problem:  at least one
auto_ptr in the sequence (the one that was a copy of
the pivot value) no longer owns the pointer it holds,
and in fact the pointer it holds has already been
deleted!

The problem with the auto_ptr in CD2 is that it gave
you no protection -- no warning, nothing -- against
innocently writing code like this.  The national body
comment required that auto_ptr be refined to either get
rid of the unusual copy semantics or else make such
dangerous code uncompilable, so that the compiler
itself could stop you from doing the dangerous things,
like making a vector of auto_ptrs or trying to sort it.


The Scoop on Non-Owning auto_ptrs
---------------------------------

         // (after having copied a to another auto_ptr)
>        cout << a->Value();
>    }

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes          No
  | Safe?     (Yes)         No

(We'll assume that a was copied, but that its pointer
wasn't deleted by the vector or the sort.)  Under CD2
this was fine, since even though a no longer owns the
pointer, it would still contain a copy of it; a just
wouldn't call delete on its pointer when a itself goes
out of scope, that's all, because it would know that it
doesn't own the pointer.

Now, however, copying an auto_ptr not only transfers
ownership but resets the source auto_ptr to null.  This
is done specifically to avoid letting anyone do
anything through a non-owning auto_ptr.  Under the
final rules, then, using a non-owning auto_ptr like
this is not legal and will result in undefined
behaviour (typically a core dump on most systems).

In short:

    void f() {
        auto_ptr<T> pt1( new T );
        auto_ptr<T> pt2( pt1 );
        pt1->Value(); // using a non-owning auto_ptr...
                      //  this used to be legal, but is
                      //  now an error
        pt2->Value(); // ok
    }

This brings us to the last common usage of auto_ptr:


Wrapping Pointer Members
-----------------1-------

>    class C {
>    public:    /*...*/
>    protected: /*...*/
>    private:
>        auto_ptr<CImpl> pimpl_;
>    };

  SUMMARY
  |         Before NJ   After NJ
  | Legal?     Yes         Yes
  | Safe?      Yes         Yes

auto_ptrs always were and still are useful for
encapsulating pointing member variables.  This works
very much like our motivating example in the
"Background" section at the beginning, except that
instead of saving us the trouble of doing cleanup at
the end of a function, it now saves us the trouble of
doing cleanup in C's destructor.

There is still a caveat, of course... just like if you
were using a bald pointer data member instead of an
auto_ptr member, you MUST supply your own copy
constructor and copy assignment operator for the class
(even if you disable them by making them private and
undefined), because the default ones will do the wrong
thing.


News Flash: The "const auto_ptr" Idiom
--------------------------------------

Now that we've waded through the deeper stuff, here's a
technique you'll find interesting.  Among its other
benefits, the refinement to auto_ptr also makes copying
const auto_ptrs illegal.  That is:

    const auto_ptr<T> pt1( new T );
        // making pt1 const guarantees that pt1 can
        // never be copied to another auto_ptr, and
        // so is guaranteed to never lose ownership

    auto_ptr<T> pt2( pt1 ); // illegal
    auto_ptr<T> pt3;
    pt3 = pt1;              // illegal

This "const auto_ptr" idiom is one of those things
that's likely to become a commonly used technique, and
now you can say that you knew about it since the
beginning.


I hope you enjoyed this Special Edition of GotW, posted in
honour of the voting out of ISO Final Draft International
Standard C++.



[1] In the original question, I forgot that there is no
conversion from T* to auto_ptr<T> because the
constructor is "explicit".  The quoted code below is
fixed.  (That's what I get for dashing this off near
midnight on Friday before rushing to New Jersey!)
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/11/19
Raw View
herbs@cntc.com (Herb Sutter) writes:

|>  >        v.push_back( auto_ptr<T>( new T(2) ) );
|>  >        sort( v.begin(), v.end() );
|>
|>    SUMMARY
|>    |         Before NJ   After NJ
|>    | Legal?     Yes          No
|>    | Safe?       No          No
|>
|>  Here's the real devil, and another reason why the
|>  national body comment was more that just a suggestion
|>  (the body in question actually voted No on CD2 largely
|>  because of this problem).  When you call generic
|>  functions that will copy elements, like sort() does,
|>  the functions have to be able to assume that copies are
|>  going to be equivalent.

I can fully understand why this one is illegal.  One question, however.
What about the following?

    auto_ptr< T > p( new T(1) ) ;
    auto_tpr< T > q( new T(2) ) ;

    swap( p ,q ) ;

Again, I cannot think of any reason why this would not work (and the
algorithm in question is simple enough that we can expect most
implementations to do what is expected).  On the other hand, I don't
think it is guaranteed under the new rules (or was guaranteed under the
old, for that matter).  Of course, it would be trivial to write my own
swap which did guarantee this, but it is a shame to not be able to use
the standard one.

The reason I ask, of course, is that my standard implementation of
operator= in a pimple class (using an auto_ptr as the pimpl) would be:

    T&
    T::operator=( T const& other )
    {
        auto_ptr< T >     newPImpl( new T( *other.pimpl ) ) ;
        swap( pimpl_ , newPImpl ) ;
        return *this ;
    }

In practice, this is by far the easiest (and in some cases, probably the
only) way of offering the strong exception safety guarantee for
assignment.

I'm currently using my own managed_ptr for this, which has a swap
member.  I would have proposed adding the function for auto_ptr, but by
the time I'd actually started using the class this way, and realized the
utility, it was far too late.  (Maybe some implementers will offer it as
an extension, but even then, using it would still limit portability.)

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
        I'm looking for a job -- Je recherche du travail
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]