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 ]