Topic: Implicit smart-to-dumb pointer conversions
Author: jodle@bix.com (jodle)
Date: 1996/06/11 Raw View
Scott Meyers (smeyers@teleport.com) wrote:
: I have mixed feelings about auto_ptr, but I prefer the new behavior to the
: old (where an auto_ptr could silently become null). auto_ptr is a
: fascinating design problem, because the conceptual specification is so
: simple, but the implementation is so troublesome. Fundamentally, I think
: it's best to think of an auto_ptr as more or less just like a dumb pointer,
: except it automatically deletes what it points to if it owns what it points
: to. Dumb pointers can silently become dangling through the actions of
: other dumb pointers, so it doesn't bother me unduly that auto_ptrs suffer
: from the same problem.
I too have mixed feeleings, but I fall slightly on the other side of the
line. I preferred auto_ptr implementations that became null. Misuse lead
to more immediate observable symptoms, making it simpler to diagnose the
cause. By definition, "sharing" implementations delay the exhibition of
these symptoms. Remember, in both scenarios we are only troubled by what
happens when things go awry; let them go spectacularly wild as soon as
possible (perhaps in unit testing!).
The diffusion of ownership represented by the current design indicates
that the purpose of the auto_ptr has itself become less clear. In my
opinion, it would be better to offer auto_ptr for guaranteeing
deallocation of memory in small scopes and a reference-counting smart
pointer for more complex situations.
[ 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: gregor@netcom.com (Greg Colvin)
Date: 1996/06/12 Raw View
In article <4pihj9$bd8@news2.delphi.com> jodle@bix.com (jodle) writes:
>
>I too have mixed feeleings, but I fall slightly on the other side of the
>line. I preferred auto_ptr implementations that became null. Misuse lead
>to more immediate observable symptoms, making it simpler to diagnose the
>cause. By definition, "sharing" implementations delay the exhibition of
>these symptoms. Remember, in both scenarios we are only troubled by what
>happens when things go awry; let them go spectacularly wild as soon as
>possible (perhaps in unit testing!).
>
It is not hard to write a conforming auto_ptr that throws an exception when
you dereference a dangling pointer, though there is some performance cost.
A simple version just implements a reference counted pointer and puts an
auto_ptr interface on it. You could use such a version for debugging and
switch to a more efficient version for production code.
---
[ 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: JdeBP@jba.co.uk (Jonathan de Boyne Pollard)
Date: 1996/06/12 Raw View
Greg Colvin (gregor@netcom.com) wrote:
| It is not hard to write a conforming auto_ptr that throws an exception when
| you dereference a dangling pointer, though there is some performance cost.
| A simple version just implements a reference counted pointer and puts an
| auto_ptr interface on it. You could use such a version for debugging and
| switch to a more efficient version for production code.
Except that you are not allowed to do that. auto_ptr is in namespace std,
and programs are not allowed to declare names in that namespace
[lib.reserved.names]. So you are stuck with whatever auto_ptr
is provided to you by the implementation.
Yes, with conditional compilation, and judicious use of typedefs, you could
get around this.
#if defined(USE_DEBUGGING_AUTO_PTR)
typedef throw_exception_auto_ptr my_auto_ptr ;
#else
typedef std::auto_ptr my_auto_ptr ;
#endif
However, the disadvantage of this is that your code is now less
legible and thus less maintainable by other people, since it now does not
reference the "standard" auto_ptr class.
If you ask me, I think that auto_ptr is not ready for standardisation. Let
the multiple different variants on auto_ptr be provided by third-party
libraries, and wait a few years to see what particular variant becomes
popular. Then standardise that one.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: willer@carolian.com (Steve Willer)
Date: 1996/06/12 Raw View
JdeBP@jba.co.uk (Jonathan de Boyne Pollard) wrote:
>Yes, with conditional compilation, and judicious use of typedefs, you could
>get around this.
>
> #if defined(USE_DEBUGGING_AUTO_PTR)
> typedef throw_exception_auto_ptr my_auto_ptr ;
> #else
> typedef std::auto_ptr my_auto_ptr ;
> #endif
Perhaps
#ifdef USE_DEBUGGING_AUTO_PTR
# define auto_ptr throw_exception_auto_ptr
#endif
....would be simpler. This code would have to be included after <memory>,
but that doesn't seem like a big deal to me.
>If you ask me, I think that auto_ptr is not ready for standardisation. Let
>the multiple different variants on auto_ptr be provided by third-party
>libraries, and wait a few years to see what particular variant becomes
>popular. Then standardise that one.
I don't much like that idea, myself. I'd prefer that compiler vendors
not pollute my namespace with tiny classes like auto_ptr if they're not
part of the standard library. I would prefer to be given the opportunity
to put together what I prefer if they're not going to offer anything
adequate 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 ]
[ 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: 1996/06/06 Raw View
In article <4ottpt$4i4@kelly.teleport.com> smeyers@teleport.com (Scott
Meyers) writes:
|> In article <009A31CF34AEC020.4980D61E@ittpub.nl>,
|> Wil Evers <wil@ittpub.nl> wrote:
|> | In article <4ognb0$3cd@linda.teleport.com> smeyers@teleport.com (Scott
|> | Meyers) writes:
|> | >
|> | > I believe that inclusion of any implicit conversion function in a
|> | > pointer-like class is asking for trouble. I describe the problem this
|> | > way in "More Effective C++":
|> |
|> | > Smart pointer classes that provide an implicit conversion to a dumb
|> | > pointer open the door to a particularly nasty bug. Consider this code:
|> | >
|> | > DBPtr<Tuple> pt = new Tuple; // DBPtr is a smart pointerobject
|> | > ...
|> | > delete pt;
|> |
|> | Do you have a similar objection to the newly defined auto_ptr, which can
|> | silently change from an owning to a non-owning (and therefore possibly
|> | dangling) auto_ptr?
|> I have mixed feelings about auto_ptr, but I prefer the new behavior to the
|> old (where an auto_ptr could silently become null). auto_ptr is a
|> fascinating design problem, because the conceptual specification is so
|> simple, but the implementation is so troublesome. Fundamentally, I think
|> it's best to think of an auto_ptr as more or less just like a dumb pointer,
|> except it automatically deletes what it points to if it owns what it points
|> to. Dumb pointers can silently become dangling through the actions of
|> other dumb pointers, so it doesn't bother me unduly that auto_ptrs suffer
|> from the same problem.
I would disagree. First, I preferred the old behavior; an auto_ptr
could only become NULL at the point where you did something to it
(assigned from it, for example), whereas now, it can start dangling
because some other auto_ptr was destructed. And of course, the problem
is precisely in the conceptual specification: what should the auto_ptr
do? Once you specify exactly what it should do, the actual
implementation doesn't cause many problems. (The fact that it dangles
exactly like a dumb pointer is an argument to consider, however. When
in doubt, stick with the problems you know, rather than inventing new
ones.)
|> The fact that there is so much controversy surrounding the semantics of
|> auto_ptr imples to me that perhaps it should not be part of the standard
|> library, but I am not on the standardization committee, so I was not
|> present when the various pros and cons were discussed. In the past,
|> whenever I've asserted that the standardization committee made a "clearly
|> dumb" decision, others with more information have shown me that the
|> decision might not have been one I'd agree with, but it was not "dumb." I
|> suspect the same is true in this case, where I can't imagine the committee
|> didn't consider the advantages of omitting auto_ptr and just letting
|> everybody write their own variants.
I'm more or less coming to the same conclusion. I would like there to
be a standard auto_ptr (and a standard counted_ptr), but I think that
the actual proposals came too late for any real consensus based on
experience to develop. Covin has done an excellent job of trying to
track what different people think they want, but what is actually needed
is several implementations, each of which does it differently. Long
term, the users would end up preferring one over the other, and that one
should make it into the standard.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
[ 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: smeyers@teleport.com (Scott Meyers)
Date: 1996/05/30 Raw View
Paul Lucas wrote about augmenting auto_ptr:
operator T*() const { return get(); }
This makes the following code legal:
auto_ptr<int> ai;
int *p = ai; // illegal otherwise
I believe that inclusion of any implicit conversion function in a
pointer-like class is asking for trouble. I describe the problem this
way in "More Effective C++":
Smart pointer classes that provide an implicit conversion to a dumb
pointer open the door to a particularly nasty bug. Consider this code:
DBPtr<Tuple> pt = new Tuple; // DBPtr is a smart pointer object
...
delete pt;
This should not compile. After all, pt is not a pointer, it's an object,
and you can't delete an object. Only pointers can be deleted, right?
Right. But remember that compilers use implicit type con-
versions to make function calls succeed whenever they can, and recall
that use of the delete operator leads to calls to a destruc-
tor and to operator delete, both of which are functions. Compilers
want these function calls to succeed, so in the delete statement
above, they implicitly convert pt to a Tuple*, then they delete that.
This will almost certainly break your program.
If pt owns the object it points to, that object is now deleted twice, once
at the point where delete is called, a second time when pt's destruc-
tor is invoked. If pt doesn't own the object, somebody else does. That
somebody may be the person who deleted pt, in which case all is well.
If, however, the owner of the object pointed to by pt is not the person
who deleted pt, we can expect the rightful owner to delete that object
again later. The first and last of these scenarios leads to an object being
deleted twice, and deleting an object more than once yields undefined
behavior.
This bug is especially pernicious because the whole idea behind smart
pointers is to make them look and feel as much like dumb pointers as
possible. The closer you get to this ideal, the more likely your clients
are to forget they are using smart pointers. If they do, who can blame
them if they continue to think that in order to avoid resource leaks,
they must call delete if they called new?
Kindly excuse the book excerpt, but the text was just SITTING there.
Think of it as reuse. I do. :-)
Scott
---
[ 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: "Wil Evers" <wil@ittpub.nl>
Date: 1996/05/30 Raw View
In article <4ognb0$3cd@linda.teleport.com> smeyers@teleport.com (Scott
Meyers) writes:
> Paul Lucas wrote about augmenting auto_ptr:
>
> operator T*() const { return get(); }
>
> This makes the following code legal:
>
> auto_ptr<int> ai;
> int *p = ai; // illegal otherwise
>
> I believe that inclusion of any implicit conversion function in a
> pointer-like class is asking for trouble. I describe the problem this
> way in "More Effective C++":
> Smart pointer classes that provide an implicit conversion to a dumb
> pointer open the door to a particularly nasty bug. Consider this code:
>
> DBPtr<Tuple> pt = new Tuple; // DBPtr is a smart pointerobject
> ...
> delete pt;
Do you have a similar objection to the newly defined auto_ptr, which can
silently change from an owning to a non-owning (and therefore possibly
dangling) auto_ptr?
- Wil
---
[ 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: "john (j.d.) hickin" <hickin@nortel.ca>
Date: 1996/05/30 Raw View
Scott Meyers (commenting on a suggestion to augment auto_ptr):
Right. But remember that compilers use implicit type con-
versions to make function calls succeed whenever they can, and recall
that use of the delete operator leads to calls to a destruc-
tor and to operator delete, both of which are functions. Compilers
want these function calls to succeed, so in the delete statement
above, they implicitly convert pt to a Tuple*, then they delete that.
This will almost certainly break your program.
It seems here that this argument allows compilers to accept the following:
char b[1];
delete[] b;
Indeed my favourite compiler accepts it [I thought it was corrected 1 release
ago but like the cat, it came back :-)].
On the other hand, gcc 2.7.2 rejects the above code, as does it reject
delete ptr; // where *ptr is a class with operator T*();
I suppose this is yet another case where we argue that compilers might detect
these problems but shouldn't be oblidged to do so.
BTW, I work around the problem by adding a private operator void*() to the
smart pointer class.
--
John Hickin Nortel Technology, Montreal, Quebec
(514) 765-7924 hickin@nortel.ca
[ 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: smeyers@teleport.com (Scott Meyers)
Date: 1996/06/03 Raw View
In article <4okqhp$lgd@bmtlh10.bnr.ca>,
john (j.d.) hickin <hickin@nortel.ca> wrote:
| Scott Meyers (commenting on a suggestion to augment auto_ptr):
|
| Right. But remember that compilers use implicit type con-
| versions to make function calls succeed whenever they can, and recall
| that use of the delete operator leads to calls to a destruc-
| tor and to operator delete, both of which are functions. Compilers
| want these function calls to succeed, so in the delete statement
| above, they implicitly convert pt to a Tuple*, then they delete that.
| This will almost certainly break your program.
|
| It seems here that this argument allows compilers to accept the following:
|
| char b[1];
| delete[] b;
Here's what the January DWP has to say about array-to-pointer
conversions:
4.2 Array-to-pointer conversion [conv.array]
1 An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to an rvalue of type "pointer to T." The result
is a pointer to the first element of the array.
So the conversion can only be applied if an rvalue is needed. However,
DWP 5.3.5 seems to allow deletion of an rvalue:
4 It is unspecified whether the deletion of an object changes its value.
If the expression denoting the object in a delete-expression is a mod
ifiable lvalue, any attempt to access its value after the deletion is
undefined (_basic.stc.dynamic.deallocation_).
I read this as allowing deletion of rvalues, which I'm pretty sure is
what is intended.
But 5.3.5 also says this (my annotations are in square brackets):
2 In either alternative [i.e., deletion of an object or deletion
of an array], if the value of the operand of delete is the null pointer
the operation has no effect. Otherwise, in the first alternative
(delete object), the value of the operand of delete shall be a pointer
[case 1: the operand must be a pointer] to a non-array object created by
a new-expression without a new-placement specification, or a pointer
[case 2: the operand must be a pointer] to a sub-object (_intro.object_)
representing a base class of such an object (_class.derived_), or an
expression of class type [case 3: the operand must be an expression of
class type] with a conversion function to pointer type
(_class.conv,fct_) which yields a pointer to such an object [which is
why the bug I posted about is explictly "supported"]. If not, the
behavior is undefined. In the second alternative (delete array), the
value of the operand of delete shall be a pointer to an array created by
a new-expression without a new- placement specification. If not, the
behavior is undefined.
As I hope my annotations show, the operand in a delete expression must
be either a pointer (before conversions are applied) or a class object
(before conversions are applied). Hence I believe the code you posted
should be rejected by compilers, though I don't know for sure whether
they are required to diagnose the problem. (I think the standard has
to use magic words like "ill-formed" before a diagnostic is required.)
| BTW, I work around the problem by adding a private operator void*() to the
| smart pointer class.
I take it you mean you provide both public operator T* and private
operator void* in your smart pointer classes. Hence implicit
conversions to T* succeed, deletion of a smart pointer is rejected due
to ambiguity, and conversions to void* (in, for example, conditionals
and calls to ==, etc.) fail because operator void* is private. Very
clever.
Scott
[ 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: smeyers@teleport.com (Scott Meyers)
Date: 1996/06/03 Raw View
In article <009A31CF34AEC020.4980D61E@ittpub.nl>,
Wil Evers <wil@ittpub.nl> wrote:
| In article <4ognb0$3cd@linda.teleport.com> smeyers@teleport.com (Scott
| Meyers) writes:
| >
| > I believe that inclusion of any implicit conversion function in a
| > pointer-like class is asking for trouble. I describe the problem this
| > way in "More Effective C++":
|
| > Smart pointer classes that provide an implicit conversion to a dumb
| > pointer open the door to a particularly nasty bug. Consider this code:
| >
| > DBPtr<Tuple> pt = new Tuple; // DBPtr is a smart pointerobject
| > ...
| > delete pt;
|
| Do you have a similar objection to the newly defined auto_ptr, which can
| silently change from an owning to a non-owning (and therefore possibly
| dangling) auto_ptr?
I have mixed feelings about auto_ptr, but I prefer the new behavior to the
old (where an auto_ptr could silently become null). auto_ptr is a
fascinating design problem, because the conceptual specification is so
simple, but the implementation is so troublesome. Fundamentally, I think
it's best to think of an auto_ptr as more or less just like a dumb pointer,
except it automatically deletes what it points to if it owns what it points
to. Dumb pointers can silently become dangling through the actions of
other dumb pointers, so it doesn't bother me unduly that auto_ptrs suffer
from the same problem.
The fact that there is so much controversy surrounding the semantics of
auto_ptr imples to me that perhaps it should not be part of the standard
library, but I am not on the standardization committee, so I was not
present when the various pros and cons were discussed. In the past,
whenever I've asserted that the standardization committee made a "clearly
dumb" decision, others with more information have shown me that the
decision might not have been one I'd agree with, but it was not "dumb." I
suspect the same is true in this case, where I can't imagine the committee
didn't consider the advantages of omitting auto_ptr and just letting
everybody write their own variants.
Scott
[ 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: 1996/06/03 Raw View
In article <4okqhp$lgd@bmtlh10.bnr.ca> "john (j.d.) hickin"
<hickin@nortel.ca> writes:
|> Scott Meyers (commenting on a suggestion to augment auto_ptr):
|> Right. But remember that compilers use implicit type con-
|> versions to make function calls succeed whenever they can, and recall
|> that use of the delete operator leads to calls to a destruc-
|> tor and to operator delete, both of which are functions. Compilers
|> want these function calls to succeed, so in the delete statement
|> above, they implicitly convert pt to a Tuple*, then they delete that.
|> This will almost certainly break your program.
|> It seems here that this argument allows compilers to accept the following:
|> char b[1];
|> delete[] b;
|> Indeed my favourite compiler accepts it [I thought it was corrected 1 release
|> ago but like the cat, it came back :-)].
It must accept it (unless it does complete flow analysis, and can prove
that the delete statement actually gets executed), since it is perfectly
legal C++. A warning wouldn't be a bad thing, however.
|> On the other hand, gcc 2.7.2 rejects the above code, as does it reject
|> delete ptr; // where *ptr is a class with operator T*();
This sounds like a bug, not a feature:-). Although again, a warning
would be nice.
|> I suppose this is yet another case where we argue that compilers might detect
|> these problems but shouldn't be oblidged to do so.
|> BTW, I work around the problem by adding a private operator void*() to the
|> smart pointer class.
Clever. But I find it easier not to support the conversion to begin
with. If I really need the raw pointer, there is always a get function
(or &*smartPtr).
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]