Topic: std::auto_ptr and inheritance based type conversion


Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Sat, 22 Jan 2005 13:38:40 GMT
Raw View
""Jonathan Turkanis"" <technews@kangaroologic.com> schrieb im Newsbeitrag
news:35dcebF4al7ssU1@individual.net...

[snip]

> In my opinion, it's best to write just the copy constructors and the
assignment
> operators, and forget the conversion operators. Some times you won't even
need
> the assignment operators.

Yes, now that I think about it, the template copy assignment operator is
unnecessary if you have a template copy constructor, because you can always
use the latter to convert to a type which you can pass as an argument to the
regular copy assignment operator. However, there might be an advantage in
performance if you also provide a template copy assignment operator.

> There are several reasons to prefer converting constructors over
conversion
> operators; unforunately the only one I can think of right now is that you
can't
> use enable_if with conversion operators. To me, this is very important,
since I
> seem to be using it a lot lately for smart pointer constructors. (I think
Scott
> Meyers lists a number of good reasons in one of his Effective C++ books.)

I have never used the boost library so far, so I don't know about enable_if.
I guess I should make myself familiar with it, as I hear about it quite
often. But first I want to make myself familiar with STL, because I have
actually just startet with it (and already ran right into the auto_ptr
pitfall...)

[snip]

> I think it's okay to use auto_ptr in scope_guard-type situations and for
> transfering ownership between callee and caller (in either direction) as
long as
> there is no conversion involved.

Yes, I forgot that the problem about auto_ptr only concerns conversions. I
wonder if it wouldn't have been better to have programmers call
'auto_ptr::release()' on the actual parameter, so that the formal parameter
can use the standard constructor, which takes a pointer.

Now that I have slept over the issue, I still wonder what is actually
*broken* about auto_ptr. The problem seems to be that only one user defined
conversion is supposed to be implicitly called, while two or three are
called in practice, as shown in "n1232.pdf" from your link. Obviously, there
is a disagreement wether this is legal for C++.

However, this rather sounds to me like the C++ standard is *broken*, not
auto_ptr. On both VC++ 6 and VC++ 7, the code shown to be problematic in
"n1232.pfd" compiles fine. Apparently, the compilers just mentioned seem to
perform more than one UDC - so are they violating the standard?

Best regards,

Matthias Hofmann



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: technews@kangaroologic.com ("Jonathan Turkanis")
Date: Sat, 22 Jan 2005 19:22:50 GMT
Raw View
"Matthias Hofmann" wrote:
> ""Jonathan Turkanis"" <technews@kangaroologic.com> schrieb im

> I have never used the boost library so far, so I don't know about
> enable_if. I guess I should make myself familiar with it, as I hear
> about it quite often.

I love it, but it's definitely not crucial to learn at first. It's mostly useful
to library writers.

>> I think it's okay to use auto_ptr in scope_guard-type situations and
>> for transfering ownership between callee and caller (in either
>> direction) as long as there is no conversion involved.
>
> Yes, I forgot that the problem about auto_ptr only concerns
> conversions. I wonder if it wouldn't have been better to have
> programmers call 'auto_ptr::release()' on the actual parameter, so
> that the formal parameter can use the standard constructor, which
> takes a pointer.

There are two problems with this approach:

- if you return a raw pointer and the calling code ignores the return value you
get a leak, which is what auto_ptr was supposed to solve.
- the auto_ptr constructor taking a raw pointer is (correctly) decalred
'explicit'

> Now that I have slept over the issue, I still wonder what is actually
> *broken* about auto_ptr.

The following table shows the 8 conversions which were supposed to be allowed,
and why two of them don't work:

http://home.comcast.net/~jturkanis/move_ptr/libs/move_ptr/doc/index.html?path=6

(Forgive me if I already posted this link.)

> The problem seems to be that only one user
> defined conversion is supposed to be implicitly called, while two or
> three are called in practice, as shown in "n1232.pdf" from your link.
> Obviously, there is a disagreement wether this is legal for C++.

Not anymore. See

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84'

The proposed resolution is now part of the standard.

> However, this rather sounds to me like the C++ standard is *broken*,
> not auto_ptr.

If auto_ptr is broker, then so is the standard ;-). But I assume you mean that
the core language is broken.

> On both VC++ 6 and VC++ 7, the code shown to be
> problematic in "n1232.pfd" compiles fine.

VC6++ uses an obsolete pre-standard auto_ptr.

As for VC7, I wonder if you mean VC7.0 or VC7.1. The example program from n1232
causes a stack overflow on VC7.1 with Dinkumware (which has since been fixed by
Dinkumware). This is mentioned by Rani Sharoni in Standard Library Issue 463,
which I already posted :

"Other vendor implemented auto_ptr_ref as defectively required and it results
with awkward and catastrophic code: int oops = sink(auto_ptr<B>(source())); //
warning recursive on all control paths"

> Apparently, the compilers
> just mentioned seem to perform more than one UDC - so are they
> violating the standard?

If they allow the copy-initialization from rvalue with derived-to-base
conversion.

> Best regards,
>
> Matthias Hofmann

Jonathan


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "KCs" <kujbus.csaba@freemail.hu>
Date: Mon, 24 Jan 2005 23:16:43 CST
Raw View
"Matthias Hofmann" wrote:
> However, this rather sounds to me like the C++ standard is *broken*,
not
> auto_ptr. On both VC++ 6 and VC++ 7, the code shown to be problematic
in
> "n1232.pfd" compiles fine. Apparently, the compilers just mentioned
seem to
> perform more than one UDC - so are they violating the standard?

We discussed some related issues in comp.lang.c++.moderated in the Is
auto_ptr_ref still needed? topic. As it turned out VC compiles the
problematic code when MS language extensions are turned on.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Thu, 27 Jan 2005 21:29:08 GMT
Raw View
""Jonathan Turkanis"" <technews@kangaroologic.com> schrieb im Newsbeitrag
news:35fl10F4lu3djU1@individual.net...

[snip]

> > The problem seems to be that only one user
> > defined conversion is supposed to be implicitly called, while two or
> > three are called in practice, as shown in "n1232.pdf" from your link.
> > Obviously, there is a disagreement wether this is legal for C++.
>
> Not anymore. See
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84'
>
> The proposed resolution is now part of the standard.

Item 84 in the link you've posted sound to me like it is now legal to call
two user defined conversions in order to do the "trick" with auto_ptr_ref?
Does that mean that auto_ptr will stay the way it is and that it will not be
considered to be broken any more? Will the code that was shown to be
problematic work with help of auto_ptr_ref?

Best regards,

Matthias Hofmann



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: technews@kangaroologic.com ("Jonathan Turkanis")
Date: Thu, 3 Feb 2005 22:35:31 GMT
Raw View
"Matthias Hofmann" wrote:
> ""Jonathan Turkanis"" schrieb:

Sorry for the long pause in this thread ....

>> Not anymore. See
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84'
>>
>> The proposed resolution is now part of the standard.

> Item 84 in the link you've posted sound to me like it is now legal to
> call two user defined conversions in order to do the "trick" with
> auto_ptr_ref? Does that mean that auto_ptr will stay the way it is
> and that it will not be considered to be broken any more? Will the
> code that was shown to be problematic work with help of auto_ptr_ref?

I interpret the resolution to *prohibit* the use of two user defined conversions
where they would otherwise have been allowed, since they occur within separate
phases of a copy-initialization. This is explained here

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf

at the top of page 3.

In any case, auto_ptr will remain broken unless Rani Sharoni's implementation
(or some completely new implementation) is made legal, perhaps by weakening the
current specification.

When you define your own classes, use Rani's technique instead of the
Colvin-Gibbons trick.

Best Regards,
Jonathan



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Sat, 5 Feb 2005 04:01:32 GMT
Raw View
""Jonathan Turkanis"" <technews@kangaroologic.com> schrieb im Newsbeitrag
news:36fjhgF4uueerU1@individual.net...
> "Matthias Hofmann" wrote:

[snip]

>
> I interpret the resolution to *prohibit* the use of two user defined
conversions
> where they would otherwise have been allowed, since they occur within
separate
> phases of a copy-initialization. This is explained here
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
>
> at the top of page 3.

My interpretation was largely influenced by the very first sentence of said
item 84:

"By the letter of the standard, the conversions required to make auto_ptr
work should be accepted."

However, the rest of the text says that the standard seems to be buggy,
which makes me doubt that my interpretation was correct. But what confuses
me most is the fact that you first said that the standard had been changed,
and now you are telling me that auto_ptr is still broken - please pardon my
ignorance, but what was the purpose of the change, then?

While dealing with that issue, there was always one question in the back of
my head: was it really necessary to make initialization in C++ such an
intricate matter? I got the suspicion that this is the result of
"documenting common practice". There were probably dozens of compilers
before the standard was written, each of which had its own unique and
bizarre way of initializing objects. And in order not to cause any trouble
to the compiler vendors, the comittee simply declared each method to be
fine.

I now that it is probably too late now, but wouldn't it have been possible
to provide a lean and mean definition for object initialization? It seems
absurd to me that object initialization is as complicated as the concept of
virtual functions...

Best regards,

Matthias



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: technews@kangaroologic.com ("Jonathan Turkanis")
Date: Mon, 14 Feb 2005 04:41:08 GMT
Raw View
"Matthias Hofmann" wrote:
> ""Jonathan Turkanis"" <technews@kangaroologic.com> schrieb:
>> "Matthias Hofmann" wrote:

> [snip]

>> I interpret the resolution to *prohibit* the use of two user defined
>> conversions where they would otherwise have been allowed, since they
>> occur within separate phases of a copy-initialization. This is
>> explained here
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
>>
>> at the top of page 3.
>
> My interpretation was largely influenced by the very first sentence
> of said item 84:
>
> "By the letter of the standard, the conversions required to make
> auto_ptr work should be accepted."
>
> However, the rest of the text says that the standard seems to be
> buggy, which makes me doubt that my interpretation was correct. But
> what confuses me most is the fact that you first said that the
> standard had been changed, and now you are telling me that auto_ptr
> is still broken - please pardon my ignorance, but what was the
> purpose of the change, then?

The purpose of the correction was not to fix auto_ptr, but to bring the core
language specifiation in line with what people expected it to say.

> While dealing with that issue, there was always one question in the
> back of my head: was it really necessary to make initialization in
> C++ such an intricate matter? I got the suspicion that this is the
> result of "documenting common practice". There were probably dozens
> of compilers before the standard was written, each of which had its
> own unique and bizarre way of initializing objects. And in order not
> to cause any trouble to the compiler vendors, the comittee simply
> declared each method to be fine.

What would be the purpose of standardization, then? Backward compatibility was
of course an important concern, but you can't be simulataneously backward
compatible with mutually inconsistent implementations. The complexity of the
rules is partially a result of  an attempt to get the language to conform to
common sense in the widest possible variety of cases. Since common sense
expectations are rarely perfectly consistent, some complexity is inevitable.

> I now that it is probably too late now, but wouldn't it have been
> possible to provide a lean and mean definition for object
> initialization? It seems absurd to me that object initialization is
> as complicated as the concept of virtual functions...

Virtual functions are really pretty simple compared to other C++ features,
aren't they? ;-)

Jonathan


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Wed, 16 Feb 2005 00:00:43 GMT
Raw View
""Jonathan Turkanis"" <technews@kangaroologic.com> schrieb im Newsbeitrag
news:379vceF5cmf7bU1@individual.net...

[snip]

>
> > While dealing with that issue, there was always one question in the
> > back of my head: was it really necessary to make initialization in
> > C++ such an intricate matter? I got the suspicion that this is the
> > result of "documenting common practice". There were probably dozens
> > of compilers before the standard was written, each of which had its
> > own unique and bizarre way of initializing objects. And in order not
> > to cause any trouble to the compiler vendors, the comittee simply
> > declared each method to be fine.
>
> What would be the purpose of standardization, then? Backward compatibility
was
> of course an important concern, but you can't be simulataneously backward
> compatible with mutually inconsistent implementations. The complexity of
the
> rules is partially a result of  an attempt to get the language to conform
to
> common sense in the widest possible variety of cases. Since common sense
> expectations are rarely perfectly consistent, some complexity is
inevitable.

Well, maybe you are right. I recently read a statement in a C++ textbook
which says that standards are not supposed to invent anything, but rather to
harmonize everything. However, I dare to say that this is a bit
contradictory: in order to reach harmony, sometimes you *do* have to make
severe changes.

I am having a dream of a perfect programming language. I don't know if this
is possible, but if yes, then it would probably have to be standardized
before it is first implemented.

Best regards,

Matthias



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Tue, 18 Jan 2005 22:09:11 GMT
Raw View
This seems to be a hard question... ;-) I am taking a wild guess now: could
it have to do with the difference between direct initialization and copy
initialization?

In other words, if my function looked like this instead:

std::auto_ptr<B> f( std::auto_ptr<D> pd )
{
     auto_ptr<B> pb( pd ); // Note: used to be 'auto_ptr<B> pb = pd;'
before.
     return pb;
 }

would the compiler be somehow compelled to call 'auto_ptr( auto_ptr<_Tp1>&
__a )' instead of 'operator auto_ptr<_Tp1>()'?

Best regards,

Matthias Hofmann


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: technews@kangaroologic.com ("Jonathan Turkanis")
Date: Fri, 21 Jan 2005 04:31:37 GMT
Raw View
"Matthias Hofmann" wrote:
> Hello!
>
> I have a question about std::auto_ptr for which I did not get an
> answer on comp.lang.c++.moderated, so I am reposting it here.
>
> I have found out that the public interface of std::auto_ptr includes
> the following two members:
>
> template <class _Tp1> auto_ptr( auto_ptr<_Tp1>& __a ) throw();
> template <class _Tp1> operator auto_ptr<_Tp1>() throw();
>
> Especially the latter one is the one that I know is required for
> inheritance based type conversion. For example:
>
> class B {};
> class D : public B {};
>
> std::auto_ptr<B> f( std::auto_ptr<D> pd )
> {
>     auto_ptr<B> pb = pd;
>     return pb;
> }
>
> In this example, an auto_ptr to a derived class is assigned to an
> auto_ptr to a base class. Now the question is, what is the compiler
> supposed to do:

See these links:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1997/N1128.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#463

> It seems to me that one of these two member functions is redundant,
> so I usually provide only the second one for my own classes.

auto_ptr is broken. Don't design your own classes based on it. If you need
something like auto_ptr, try move_ptr:

http://home.comcast.net/~jturkanis/move_ptr/

Jonathan


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Fri, 21 Jan 2005 21:35:53 GMT
Raw View
----- Original Message -----
From: ""Jonathan Turkanis"" <technews@kangaroologic.com>
Newsgroups: comp.std.c++
Sent: Friday, January 21, 2005 5:31 AM
Subject: Re: std::auto_ptr and inheritance based type conversion


[snip]

>
> auto_ptr is broken. Don't design your own classes based on it. If you need
> something like auto_ptr, try move_ptr:
>
> http://home.comcast.net/~jturkanis/move_ptr/
>

Thank you very much. The links were rather helpful, although very
confusing... :-(

However, I still wonder what the approved way of implementing inheritance
based type conversion is, assuming I want to be able to use copy
construction and copy assignment. It seems to me that providing a user
defined template conversion operator makes both the template copy
constructor and the template copy assignment operator unnecessary - or
should I rather provide them and renounce the conversion operator instead?

And one more thing about auto_ptr: do you think that in the face of all
these problems, it is better not to use auto_ptr at all until a solution is
found?

Best regards

Matthias Hofmann



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: technews@kangaroologic.com ("Jonathan Turkanis")
Date: Fri, 21 Jan 2005 22:25:15 GMT
Raw View
"Matthias Hofmann" wrote:

> Thank you very much. The links were rather helpful, although very
> confusing... :-(

Yeah, I know. It's amazing how complicated this simple little utility turned out
to be.

> However, I still wonder what the approved way of implementing
> inheritance based type conversion is, assuming I want to be able to
> use copy construction and copy assignment. It seems to me that
> providing a user defined template conversion operator makes both the
> template copy constructor and the template copy assignment operator
> unnecessary - or should I rather provide them and renounce the
> conversion operator instead?

In my opinion, it's best to write just the copy constructors and the assignment
operators, and forget the conversion operators. Some times you won't even need
the assignment operators.

There are several reasons to prefer converting constructors over conversion
operators; unforunately the only one I can think of right now is that you can't
use enable_if with conversion operators. To me, this is very important, since I
seem to be using it a lot lately for smart pointer constructors. (I think Scott
Meyers lists a number of good reasons in one of his Effective C++ books.)

> And one more thing about auto_ptr: do you think that in the face of
> all these problems, it is better not to use auto_ptr at all until a
> solution is found?

I think it's okay to use auto_ptr in scope_guard-type situations and for
transfering ownership between callee and caller (in either direction) as long as
there is no conversion involved.

If you need a lightweight smart pointer for transfering ownserhip which handles
conversions correctly, the move_ptr I posted is free. (It is also used as an
implementation detail in Thorsten Ottosen's smart container library recently
accepted into boost.)

> Best regards
>
> Matthias Hofmann

Jonathan


---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hofmann@anvil-soft.com ("Matthias Hofmann")
Date: Wed, 12 Jan 2005 07:34:58 GMT
Raw View
Hello!

I have a question about std::auto_ptr for which I did not get an answer on
comp.lang.c++.moderated, so I am reposting it here.

I have found out that the public interface of std::auto_ptr includes the
following two members:

template <class _Tp1> auto_ptr( auto_ptr<_Tp1>& __a ) throw();
template <class _Tp1> operator auto_ptr<_Tp1>() throw();

Especially the latter one is the one that I know is required for inheritance
based type conversion. For example:

class B {};
class D : public B {};

std::auto_ptr<B> f( std::auto_ptr<D> pd )
{
    auto_ptr<B> pb = pd;
    return pb;
}

In this example, an auto_ptr to a derived class is assigned to an auto_ptr
to a base class. Now the question is, what is the compiler supposed to do:

1. Call 'auto_ptr<B>( auto_ptr<D>& __a )' to create 'pb' from 'pd'
or
2. Call 'auto_ptr<D>::operator auto_ptr<B>() to do the conversion

It seems to me that one of these two member functions is redundant, so I
usually provide only the second one for my own classes. Or can anyone give
me an example where the template copy constructor is needed because the
conversion operator won't work?

Best regards,

Matthias Hofmann



---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]