Topic: auto_ptr_ref


Author: Jason Merrill <jason@cygnus.com>
Date: 1998/05/23
Raw View
>>>>> Greg Colvin <gcolvin@us.oracle.com> writes:

> (3) Direct-initialization, base-from-derived, e.g.

>           struct Base {};
>           struct Derived : Base {};
>           auto_ptr<Derived> source();

>           auto_ptr<Base> p( source() );

>   This is similar to (1); in this case, the viable constructor is:

>          auto_ptr<Base>::auto_ptr(auto_ptr_ref<Base>)

>   which is callable using the conversion

>          auto_ptr<Derived>::operator auto_ptr_ref<Base>()

>   which should be selected when operator overloading tries to
>   convert type auto_ptr<Derived> to auto_ptr_ref<Base>.

>   Overload resolution succeeds.  No additional copying is allowed,
>   so the copy constructor need not be callable.

This doesn't work, because auto_ptr_ref is a nested class template,
and auto_ptr<Derived>::auto_ptr_ref<Base> is a distinct type from
auto_ptr<Base>::auto_ptr_ref<Base>.  If you move auto_ptr_ref to file
scope, this works.

Jason


[ 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: "Greg Colvin" <gcolvin@us.oracle.com>
Date: 1998/05/22
Raw View
Bjorn Fahller asks:
> Could someone with knowledge of the auto_ptr_ref<T> type tell
> me what it's supposed to do, how it's supposed to work and how
> it's supposed to be used?

Dave Abraham's explains that:
> Basically the problem is as follows:
>
> 1. auto_ptr<T>'s copy constructor has a non-const rhs
> 2. you're not allowed to pass a non-const reference to a temporary

This causes various difficulties that auto_ptr_ref solves.

Following is part of a committee paper that I co-authored, wherein
Bill Gibbons explains in detail what problems auto_ptr_ref solves
and how it solves them.

Greg Colvin
___________________________________________________________________

Analysis of Conversion Operations

There are four cases to consider: direct-initialization and copy-
initialization (8.5/14) for both same-type initialization and base-
from-derived initialization.

(1) Direct-initialization, same type, e.g.

          auto_ptr<int> source();

          auto_ptr<int> p( source() );

  This is considered a direct call to a constructor of
  auto_ptr<int>,using overload resolution.  There is only one
  viable constructor:

         auto_ptr<int>::auto_ptr(auto_ptr_ref<int>)

  which is callable using the conversion

         auto_ptr<int>::operator auto_ptr_ref<int>()

  which should be selected when operator overloading tries to
  convert type auto_ptr<int> to auto_ptr_ref<int>.

  Overload resolution succeeds.  No additional copying is allowed,
  so the copy constructor need not be callable.

(2) Copy-initialization, same type, e.g.

          auto_ptr<int> source();
          void sink( auto_ptr<int> );

          main() {
              sink( source() );
          }

  According to 8.5/14:

     If the initialization is direct-initialization, or if it is
     copy-initialization where the cv-unqualified version of the
     source type is the same class as, or a derived class of, the
     class of the destination, constructors are considered...

  So this case is handled the same as the direct-initialization
  case.

(3) Direct-initialization, base-from-derived, e.g.

          struct Base {};
          struct Derived : Base {};
          auto_ptr<Derived> source();

          auto_ptr<Base> p( source() );

  This is similar to (1); in this case, the viable constructor is:

         auto_ptr<Base>::auto_ptr(auto_ptr_ref<Base>)

  which is callable using the conversion

         auto_ptr<Derived>::operator auto_ptr_ref<Base>()

  which should be selected when operator overloading tries to
  convert type auto_ptr<Derived> to auto_ptr_ref<Base>.

  Overload resolution succeeds.  No additional copying is allowed,
  so the copy constructor need not be callable.

(4) Copy-initialization, base-from-derived, e.g.

          struct Base {};
          struct Derived : Base {};
          auto_ptr<Derived> source();
          void sink( auto_ptr<Base> );

          main() {
              sink( source() );
          }

  This case is not similar to (2), because the sentence quoted
  above from 8.5/14 does not apply. So there must be a conversion
  function (operator or constructor) from the argument type to the
  parameter type, and it will be used to initialize a temporary
  variable.  Note that this initialization process does not
  involve use of a copy constructor:

  The user-defined conversion so selected is called to convert the
  initializer expression into a temporary, whose type is the type
  returned by the call of the user-defined conversion function,
  with the cv-qualifiers of the destination type.

  The parameter type is auto_ptr<Base>, so there must be a
  conversion from auto_ptr<Derived> to auto_ptr<Base>. The
  constructor

          auto_ptr<Base>::auto_ptr<Derived>(auto_ptr<Derived> &)

  does not work because the argument is an rvalue.  But the
  conversion function

          auto_ptr<Derived>::operator auto_ptr<Base>()

  does work.  The result of calling this conversion function is a
  temporary - no copy constructor is needed.

  Once the temporary has been created, the draft says:

     The object being initialized is then direct-initialized from
     the temporary according to the rules above.

  This direct-initialization is case (1) which works.

At no time in any of these four cases is the implementation
allowed to make an unnecessary copy of an auto_ptr object.
Therefore it does not matter that the copy constructor does not
work on rvalues.



[ 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@gibbons.org (Bill Gibbons)
Date: 1998/05/28
Raw View
In article <u91ztlpl7n.fsf@yorick.cygnus.com>, Jason Merrill
<jason@cygnus.com> wrote:

> >>>>> Greg Colvin <gcolvin@us.oracle.com> writes:
>
> > (3) Direct-initialization, base-from-derived, e.g.
>
> >           struct Base {};
> >           struct Derived : Base {};
> >           auto_ptr<Derived> source();
>
> >           auto_ptr<Base> p( source() );
>
> >   This is similar to (1); in this case, the viable constructor is:
>
> >          auto_ptr<Base>::auto_ptr(auto_ptr_ref<Base>)
>
> >   which is callable using the conversion
>
> >          auto_ptr<Derived>::operator auto_ptr_ref<Base>()
>
> >   which should be selected when operator overloading tries to
> >   convert type auto_ptr<Derived> to auto_ptr_ref<Base>.
>
> >   Overload resolution succeeds.  No additional copying is allowed,
> >   so the copy constructor need not be callable.
>
> This doesn't work, because auto_ptr_ref is a nested class template,
> and auto_ptr<Derived>::auto_ptr_ref<Base> is a distinct type from
> auto_ptr<Base>::auto_ptr_ref<Base>.  If you move auto_ptr_ref to file
> scope, this works.

Offhand that looks correct.  Of course, rather than put auto_ptr_ref in
file scope, you could put it in a non-template base class.

The intent is that auto_ptr_ref is just an implementation detail.
We almost decided to omit it (as many implementation details are
omitted in the FDIS) but the details of how auto_ptr works for
derived-to-base conversions are already sufficiently obscure without
hiding auto_ptr_ref.

-- Bill Gibbons
   bill@gibbons.org


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