Topic: delete of const objects o.k.?


Author: David R Tribble <david@tribble.com>
Date: 1999/10/12
Raw View
Gabriel Dos_Reis wrote:
>
> David R Tribble <david@tribble.com> writes:
>
> [...]
>
> | You seem to be assuming that the following is less likely to be
> | written "accidentally" because a reference is used instead of a
> | pointer:
> |
> |     void foo(const Type &t)
> |     {
> |         ...
> |         delete &t;
> |     }
> |
> | I wouldn't make that assumption.
>
> Following that logic, I'd conclude that
>
>         delete const_cast<T*>(p);
>
> can be written accidentally.
>
> Deletion *is* a perilous operation and everybody thinks or should
> think about it more than once.

That's the problem.  Can you ensure that clients of your code will
not delete the objects owned by your code?  What forces a programmer
to think about deletion more than once?

-- David R. Tribble, david@tribble.com, http://www.david.tribble.com --


[ 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: David R Tribble <david@tribble.com>
Date: 1999/10/12
Raw View
Toby Dickenson wrote:
>
> sbnaran@uiuc.edu (Siemel B. Naran) wrote:
>
>> Indeed, in code reviews the phrase "something_cast<...>(...)" always
>> stands out.  This puts us in alert mode, and in our review, we tend
>> to read the code more carefully.  And deleting a constant thing (ie,
>> deleting a pointer to const) is something that should stand out in
>> code reviews, and so we should have to use "const_cast".
>
> Arguably, any use of a raw 'delete' outside the implementation of a
> smart pointer should be called into question at review.
>
> To require a const_cast in this case would only duplicate the danger
> signals.

So you're saying that allowing deletion of pointers-to-const is okay
because everyone should be using smart pointers anyway?  All that
'const_cast<>()' nonsense is just useless extra typing, right?

-- David R. Tribble, david@tribble.com, http://www.david.tribble.com --


[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/10/12
Raw View
In article <38030232$0$221@nntp1.ba.best.com>,
Nathan Myers <ncm@nospam.cantrip.org> wrote:

>Francis, if you are invoking the "const is useless anyhow" argument,
>you need to explain how it is useful for the compiler to emit an
>error message for assigning through (the wrong) pointer-to-const,
>but not for deleting (the wrong) pointer-to-const.

>Or would you argue that all enforcement of restrictions on
>pointer-to-const operations is equally inconvenient and undesirable?

I have already explained it, but I'll explain it again in case you
missed it the first time.

The ability to delete an object successfully is a fundamentally different
kind of property from the ability to assign to an object.

The difference is that assignment behaves the same way for all objects
of a given type, but deletion does not behave the same way for all
objects of a given type.

This difference makes it reasonable to argue that the deletion property
should not be part of the object's type, while still arguing that the
assignment property should be part of the object's type.

I understand that not everyone agrees with the argument.  That's not the
point, though -- the point is that the argument is well-formed whether
you agree with it or not, and what makes the argument well-formed is the
fundamental difference in behavior between assignment and deletion.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: James Dennett <james@jamesd.demon.co.uk>
Date: 1999/10/12
Raw View
Nathan Myers wrote:

> Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
> > Al Stevens <alstevens@midifitz.com> writes
> >>>>BTW, if you want safety from 'accidental' delete why are you not passing
> >>>>by reference?
> >>>
> >>>Excuse me, but we're talking about real programs here.  References
> >>>are appropriate in many places but they are not the universal elixir.
> >>
> >>And, of course, the obvious response: I cannot pass by reference if the
> >>library function expects me to pass an address argument to a pointer
> >>parameter. It's not the passer who is likely to foul; it's the receiver,
> >>and, to confuse the metaphor, the receiver is often on a different team.
> >
> >We all (have to) use bad code sometimes. However if that code also
> >deletes what it is given access to without clearly warning the user via
> >its name or other documentation) then it would fail even the most
> >rudimentary of QA and should be rejected in any competent environment.
>
> Francis, if you are invoking the "const is useless anyhow" argument,
> you need to explain how it is useful for the compiler to emit an
> error message for assigning through (the wrong) pointer-to-const,
> but not for deleting (the wrong) pointer-to-const.

This is a genuine question to Nathan, and *not* an attack.

Nathan: as it is "obvious" to me that nobody here has claimed that "const is
useless anyhow", why do you invoke the phrase?  Is it an attempt to illustrate
the technique of using fallacious or illogical arguments to argue for an
otherwise possibly-valid conclusion?

Just wondering, before I finally give up on this thread as going nowhere.

-- James Dennett <jdennett@acm.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/13
Raw View
James Dennett  <james@jamesd.demon.co.uk> wrote:
>Nathan Myers wrote:
>> Francis, if you are invoking the "const is useless anyhow" argument,
>> you need to explain how it is useful for the compiler to emit an
>> error message for assigning through (the wrong) pointer-to-const,
>> but not for deleting (the wrong) pointer-to-const.
>
>Nathan: as it is "obvious" to me that nobody here has claimed that
>"const is useless anyhow", why do you invoke the phrase?  Is it an
>attempt to illustrate the technique of using fallacious or illogical
>arguments to argue for an otherwise possibly-valid conclusion?

In fact, Andrew _has_ claimed that the protections afforded const in
the disputed context were "not useful".  (Const certainly is useless
there _now_ -- it is entirely ignored.)  If you would prefer another
shorthand name for the argument, please suggest it.   Better, try to
answer my question to Francis --  I am interested more in the arguments
than in the names we remember them by.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/13
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>Nathan Myers <ncm@nospam.cantrip.org> wrote:
>
>>Francis, if you are invoking the "const is useless anyhow" argument,
>>you need to explain how it is useful for the compiler to emit an
>>error message for assigning through (the wrong) pointer-to-const,
>>but not for deleting (the wrong) pointer-to-const.
>
>>Or would you argue that all enforcement of restrictions on
>>pointer-to-const operations is equally inconvenient and undesirable?
>
>I have already explained it, but I'll explain it again in case you
>missed it the first time.

Andrew, repeating an argument that has already failed to support your
assertion does not improve it.

>The ability to delete an object successfully is a fundamentally different
>kind of property from the ability to assign to an object.

That is the original claim that started this discussion.  Thus far
none of the arguments in its support has withstood scrutiny.

>The difference is that assignment behaves the same way for all objects
>of a given type, but deletion does not behave the same way for all
>objects of a given type.

Each behaves the same way _everywhere_ it is defined.  The language
can, and once did, help identify cases where it is not defined.

>This difference makes it reasonable to argue that the deletion property
>should not be part of the object's type, while still arguing that the
>assignment property should be part of the object's type.

Interestingly, the difference that Andrew tries to point out actually
argues the opposite of what he claims.  The set of cases where deletion
is undefined _is_ different from those where assignment is undefined:
the latter is a subset of the former.

This fact argues for _more_ protection applied to delete-expressions,
because a wider variety of errors may be guarded against by such
protection.  Alternatively, it argues for eliminating such protection
from assignment, where fewer such errors are possible, because those
that remain are also ignored in delete-expressions.  The call to show
how deletion is less deserving of protection than assignment has resulted
in Andrew demonstrating the opposite.

>I understand that not everyone agrees with the argument.  That's not the
>point, though -- the point is that the argument is well-formed whether
>you agree with it or not, and what makes the argument well-formed is the
>fundamental difference in behavior between assignment and deletion.

Andrew's latest argument is not of the same brand of invalidity as
many previous; its problems stem directly from details of the argument.
However, besides its internal problem (arguing for the opposite of the
claim it was offered to support) this argument fails like several of
the others in that it appeals only to internal logic of the language,
without considering any engineering consequences of the alternatives.

If, as we have all said we accept (and Andrew has been at pains to
repeat), the issue voted on was a judgment call, then any argument which
claims to support one side without addresing any actual consequences
of the alternatives is necessarily irrelevant to the point.

Many logically-invalid arguments have been offered.  It would help
advance discussion if the invalidity of those were acknowledged by
their proponents to have been demonstrated, so that we may avoid
going over old ground again and again.

I invite Andrew (again!) to come clean and acknowledge that the
Unix file system analogy, for instance, was spurious.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/10/14
Raw View
Al Stevens wrote:
>
> >>BTW, if you want safety from 'accidental' delete why are you not passing
> >>by reference?
> >
> >Excuse me, but we're talking about real programs here.  References
> >are appropriate in many places but they are not the universal elixir.
>
> And, of course, the obvious response: I cannot pass by reference if the
> library function expects me to pass an address argument to a pointer
> parameter. It's not the passer who is likely to foul; it's the receiver,
> and, to confuse the metaphor, the receiver is often on a different team.

And I can't pass a const object if the function expect a
non-const object as well, even if that function does not
modify the object.

However, if we have a reference and use the address-of operator
to get a pointer, it's obvious that we are responsible for
checking that the function does not delete the object, just as
we are responsible for checking that the function does not
really modify the object if we are using a const_cast.
---
[ 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: Toby Dickenson <htrd90@zepler.org>
Date: 1999/10/14
Raw View
David R Tribble <david@tribble.com> wrote:

>Toby Dickenson wrote:
>>
>> sbnaran@uiuc.edu (Siemel B. Naran) wrote:
>>
>>> Indeed, in code reviews the phrase "something_cast<...>(...)" always
>>> stands out.  This puts us in alert mode, and in our review, we tend
>>> to read the code more carefully.  And deleting a constant thing (ie,
>>> deleting a pointer to const) is something that should stand out in
>>> code reviews, and so we should have to use "const_cast".
>>
>> Arguably, any use of a raw 'delete' outside the implementation of a
>> smart pointer should be called into question at review.
>>
>> To require a const_cast in this case would only duplicate the danger
>> signals.
>
>So you're saying that allowing deletion of pointers-to-const is okay
>because everyone should be using smart pointers anyway?

It's clearly not an argument _for_ that change, merely a reason for
not mourning that change.

>All that
>'const_cast<>()' nonsense is just useless extra typing, right?

I wouldn't describe the ARM restriction as 'nonsense', but I don't see
it has any merit in this scenario.



Toby Dickenson
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/10/11
Raw View
In article <deJL3.2927$Uw.162092@newscene.newscene.com>, Al Stevens
<alstevens@midifitz.com> writes
>>>BTW, if you want safety from 'accidental' delete why are you not passing
>>>by reference?
>>
>>Excuse me, but we're talking about real programs here.  References
>>are appropriate in many places but they are not the universal elixir.
>
>And, of course, the obvious response: I cannot pass by reference if the
>library function expects me to pass an address argument to a pointer
>parameter. It's not the passer who is likely to foul; it's the receiver,
>and, to confuse the metaphor, the receiver is often on a different team.

We all (have to) use bad code sometimes. However if that code also
deletes what it is given access to without clearly warning the user via
its name or other documentation) then it would fail even the most
rudimentary of QA and should be rejected in any competent environment.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: Mike Enright <enrightm@acm.org>
Date: 1999/10/11
Raw View
ark@research.att.com (Andrew Koenig) wrote:
<...>
>
>It might make sense to extend the type system to include deletability
>as an attribute, but if so, I do not believe that overloading const is
>the right way to go about it.

Is this the basis on which the matter was debated in the committee?

What about benefits? The only pragmatic argument I've ever heard in
favor of the change was accompanied by an example. That example was
shown, by another writer, to be surmountable without making the change
to the semantics of const. On the other hand, the pre-existing
situation was that certain pointers were not deletable, unless you did
something obvious. And that has been of some benefit.

I believe I have read in this thread the argument that, since the
nondeletability could be circumvented in practice, it was pointless in
practice. Since friend declarations can be inserted into class
declarations, with some effort and in technical violation of the ODR,
does that diminish the value of the class, protected, or private
keywords? I have had several awkward experiences with C interfaces
which were supposed to be useable from C++, yet used 'class' as a
parameter name or struct member's name. Maybe some other folks have
had the same experience, and would like to see some changes to C++.

Maybe not.


--
Mike Enright
enrightm@acm.org (Email replies cheerfully ignored, use the news group)
http://www.users.cts.com/sd/m/menright/
Cardiff-by-the-Sea, California, USA
---
[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/10/11
Raw View
In article <xYABOOpxEt7rk5I7WXaLwZ5g1u=x@4ax.com>,
Mike Enright  <enrightm@acm.org> wrote:
>ark@research.att.com (Andrew Koenig) wrote:

>>It might make sense to extend the type system to include deletability
>>as an attribute, but if so, I do not believe that overloading const is
>>the right way to go about it.

>Is this the basis on which the matter was debated in the committee?

No, it's an argument that I formed recently in response to the
current discussion.

>What about benefits? The only pragmatic argument I've ever heard in
>favor of the change was accompanied by an example. That example was
>shown, by another writer, to be surmountable without making the change
>to the semantics of const. On the other hand, the pre-existing
>situation was that certain pointers were not deletable, unless you did
>something obvious. And that has been of some benefit.

Obvious is a matter of opinion.  You might, for example call a chain
of functions several levels deep, at the end of which is one for which
you don't have the source code.

But whether or not it's obvious doesn't affect the fact that it exists,
and that I and some other people believe that if you allocate an object,
you should be able to deallocate it without special formality.

I acknowledge that this point of view is not universally held, and
that it is a matter of opinion.  I will not agree that my viewpoint
is objectively invalid and anyone who holds it is being illogical.

>I believe I have read in this thread the argument that, since the
>nondeletability could be circumvented in practice, it was pointless in
>practice. Since friend declarations can be inserted into class
>declarations, with some effort and in technical violation of the ODR,
>does that diminish the value of the class, protected, or private
>keywords? I have had several awkward experiences with C interfaces
>which were supposed to be useable from C++, yet used 'class' as a
>parameter name or struct member's name. Maybe some other folks have
>had the same experience, and would like to see some changes to C++.

This analogy doesn't apply, because the question is about what should
be possible in programs whose behavior the standard guarantees.
Programs that violate ODR do not have guaranteed behavior.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: Toby Dickenson <htrd90@zepler.org>
Date: 1999/10/11
Raw View
sbnaran@uiuc.edu (Siemel B. Naran) wrote:

>Indeed, in code reviews the phrase "something_cast<...>(...)" always
>stands out.  This puts us in alert mode, and in our review, we tend to
>read the code more carefully.  And deleting a constant thing (ie,
>deleting a pointer to const) is something that should stand out in
>code reviews, and so we should have to use "const_cast".

Arguably, any use of a raw 'delete' outside the implementation of a
smart pointer should be called into question at review.

To require a const_cast in this case would only duplicate the danger
signals.



Toby Dickenson


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/12
Raw View
Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
> Al Stevens <alstevens@midifitz.com> writes
>>>>BTW, if you want safety from 'accidental' delete why are you not passing
>>>>by reference?
>>>
>>>Excuse me, but we're talking about real programs here.  References
>>>are appropriate in many places but they are not the universal elixir.
>>
>>And, of course, the obvious response: I cannot pass by reference if the
>>library function expects me to pass an address argument to a pointer
>>parameter. It's not the passer who is likely to foul; it's the receiver,
>>and, to confuse the metaphor, the receiver is often on a different team.
>
>We all (have to) use bad code sometimes. However if that code also
>deletes what it is given access to without clearly warning the user via
>its name or other documentation) then it would fail even the most
>rudimentary of QA and should be rejected in any competent environment.

Francis, if you are invoking the "const is useless anyhow" argument,
you need to explain how it is useful for the compiler to emit an
error message for assigning through (the wrong) pointer-to-const,
but not for deleting (the wrong) pointer-to-const.

Or would you argue that all enforcement of restrictions on
pointer-to-const operations is equally inconvenient and undesirable?

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/09
Raw View
Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
> Alexandre Oliva <oliva@lsd.ic.unicamp.br> writes
>>Now you're talking about safety of `delete', which is a completely
>>different issue, IMHO.  If you want safety from deleting the wrong
>>object, you have to go for garbage collection or something like that;
>>new/delete just can't get you there.
>
>BTW, if you want safety from 'accidental' delete why are you not passing
>by reference?

Excuse me, but we're talking about real programs here.  References
are appropriate in many places but they are not the universal elixir.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/10/09
Raw View
In article <37FD34F6.4117CAB7@tribble.com>, David R Tribble
<david@tribble.com> writes
>    void foo(const Type &t)
>    {
>        ...
>        delete &t;
>    }
>
>I wouldn't make that assumption.

But grepping for delete &  (with a suitable spec to handle variable
amounts of whitespace) would be easy and any cases found would
definitely be highly suspect.  I would definitely require a quite
exceptional justification for delete &  from any programmer.

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/10/10
Raw View
>>BTW, if you want safety from 'accidental' delete why are you not passing
>>by reference?
>
>Excuse me, but we're talking about real programs here.  References
>are appropriate in many places but they are not the universal elixir.

And, of course, the obvious response: I cannot pass by reference if the
library function expects me to pass an address argument to a pointer
parameter. It's not the passer who is likely to foul; it's the receiver,
and, to confuse the metaphor, the receiver is often on a different team.
---
[ 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: David R Tribble <david@tribble.com>
Date: 1999/10/08
Raw View
Francis Glassborow wrote:
>
> Alexandre Oliva <oliva@lsd.ic.unicamp.br> writes:
>> Now you're talking about safety of 'delete', which is a completely
>> different issue, IMHO.  If you want safety from deleting the wrong
>> object, you have to go for garbage collection or something like that;
>> new/delete just can't get you there.
>
> BTW, if you want safety from 'accidental' delete why are you not
> passing by reference?

You seem to be assuming that the following is less likely to be
written "accidentally" because a reference is used instead of a
pointer:

    void foo(const Type &t)
    {
        ...
        delete &t;
    }

I wouldn't make that assumption.

-- David R. Tribble, david@tribble.com, http://www.david.tribble.com --
---
[ 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: danil@ultranet.com (Danil)
Date: 1999/10/08
Raw View
In article <37fcedaa$0$215@nntp1.ba.best.com>, ncm@nospam.cantrip.org
says...
> Const _never_ protected against destruction.  It protected against
> improper deletion -- and assignment.

What is the value of "destructible, but not deletable"?

[Disclaimer: D&E is sitting on my night reading table.  If the issue is
discussed there, I need to read further.]

It seems to me that, starting from scratch, you might decide that read-
only is orthogonal to lifetime management.  Alternatively, you might
decide that read-only means precisely that - you aren't allowed to do
anything but read.  Judging from the signal of this thread, this appears
to be a judgment call.

This is, of course, different from starting with an existing set of
rules, and deciding what changes, if any, are appropriate.  Two
possibilities, which were of equivalent merit when no code existed, may
have vastly differing impacts upon the existing code base.

Although one or more possible changes may have merit, the arguments in
favor of leaving the current rules alone may have sufficient inertia to
counter any change.  Arguments that suggest a lot of inertia might well
include:

"Currently conforming code will no longer be conforming."
"Currently conforming code will continue to be conforming, but will have
different behavior."

In contrast, the argument against changing delete [T const *] doesn't
suggest very much inertia:

"Currently conforming code will be vulnerable to error in new code
written by clients when using expressions where care has always been
required."[1]

To my view, even a small step toward improved consistency is enough to
counter it.  "If you can destroy it, then you can delete it"[2] seems a
pretty good rule to me - I don't particularly care whether that means
that delete [T const *] is legal or instead [T const *]->~T() is illegal.
It looks like the toss up above to me; more experienced hands may know
differently.


Sidebar: is it really appropriate to criticize the proponents of a change
for failing to provide an objective engineering analysis when the
proponents for stasis could also have provided that analysis and choose
not to do so?  I haven't seen the standardization process in action, so
I don't know what groundwork is supposed to occur before a change is
voted in.

Danil

[1] when writing "delete p;", the client has to know whether he owns p.

[2] perhaps too vaguely expressed - mea maxima


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/08
Raw View
Alexandre Oliva  <oliva@lsd.ic.unicamp.br> wrote:
>On Oct  7, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:
>> Alexandre Oliva  <oliva@lsd.ic.unicamp.br> wrote:
>>> On Oct  4, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:
>>>> You cannot insert a const_cast accidentally, so lifetime errors
>>>> from deleting "the wrong thing" were correspondingly harder.
>>>> That protection is gone now.
>>>
>>> Now you're talking about safety of `delete', which is a completely
>>> different issue, IMHO.
>>
>> The _only_ aspect of const semantics that was changed was how (whether)
>> it applied to delete-expressions.  Anything else would be a different
>> issue.
>
>I meant that delete const isn't the only unsafe aspect of delete.
>There are so many others that I don't think there's anything so
>special about this one that it deserves so much attention.  I prefer
>to consider plain pointers unsafe at best, and, if you need any
>protection, you need some kind of smart pointer.

*All* the unsafe aspects of delete were protected against, for
pointers-to-const.  That pointers-to-non-const got (and get) no
protection did not detract from the protection that we did have.

We've been through this before, already:

That the language lacked potentially useful feature X' is not a
sensible reason to eliminate limited but still-useful feature X.
(The same reasoning would eliminate unsigned long because we lack
support for long long -- and eliminate all enforcement of const
whatsoever.)

>> The point was to allow code to pass around pointers -- not
>> necessarily to dynamic storage -- and be assured that nothing would
>> damage them.  It did work for that, but no longer does.
>
>It didn't, because:
>
>> Const _never_ protected against destruction.  It protected against
>> improper deletion -- and assignment.
>
>Since someone (for example, the template function `foo' below) could
>still invoke the destructor for the object pointed by the pointer you
>gave them, even if the pointer was to a const-qualified version of the
>object's type, there's no guarantee that the object won't be messed up
>with.  Therefore the whole discussion is pointless.

Again, you're arging that the lack of an unrelated feature -- protection
against a direct call to the destructor -- made this feature useless.
Industrial practice proves that wrong: the feature _was_ heavily used.

Adding protection against destruction would have broken code.  It
might have been useful, but in any case explicit destruction attracts
a lot of attention because it is very rarely needed.

I could use your same argument to claim that protection against
assigning through a pointer-to-const is useless, because after
all I can always destroy and reconstruct the object with a new
value.  Nonetheless, it was the rule for delete that was changed,
and not the rule for assignment.

So far you haven't distinguished deletion from assignment.

>One proposal that would lead to some advance in the direction you
>want ... renders the following constructs ill-formed:
>
>template <typename T> void foo(T const *p) {
>  p->~T(); // error, cannot destruct const object
>  new (p) T; // already invalid, casting p to void* discards const
>  p = new const T; // error, cannot construct const object
>  delete p; // error, cannot destruct const object
>}

Something like this might have been desirable, but have would
broken existing code, so it was not proposed.

>IMHO, prohibiting deletion of const without prohibiting destruction of
>const is pointless.  The exceptions in the wording above sound (to me)
>much more natural than the exception on delete of const.  Ruling away
>delete of const sounds arbitrary and doesn't accomplish the intended
>benefit, while the exceptions for constness violations at construction
>and destruction time already exist and are necessary for const to be
>usable.

The argument above applies equally well to eliminating all enforcement
of const restrictions.

Deletion was once one among many operations const protected against;
it has indeed been singled out, and for very "arbitrary" reasons --
including the logically-invalid ones I have been carrying on about
-- for elimination.  I agree with you that there was no good reason to
single it out.

In particular, that destruction was singled out for no better reason
than history was not a good reason also to single out deletion.

>template <typename T>
>void foo(T /*const*/ *p) { // assume deduced const
>  typedef typename cv_unqualified<T>::type Tu;
>  const_cast<Tu *>(p)->~Tu();
>  new (const_cast<void*>(p)) Tu;
>  p = new Tu;
>  delete const_cast<Tu *>(p);
>}
>
>It doesn't even look that bad.  But it would require a lot of code to
>be rewritten :-(

Agreed.

Still, in practice, anybody who makes an explicit destructor call is
working with raw storage anyway, and would not welcome or benefit from
type system enforcement.  Junior coders do not need to do it, and
(in well-run shops) are not allowed to use it.

For your arguments above to carry any weight, you need to show
how protections against deletion were less useful than protection
against assignment in the same context.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1999/10/08
Raw View
In article <37fd903e$0$219@nntp1.ba.best.com>,
Nathan Myers <ncm@nospam.cantrip.org> wrote:

>That the language lacked potentially useful feature X' is not a
>sensible reason to eliminate limited but still-useful feature X.
>(The same reasoning would eliminate unsigned long because we lack
>support for long long -- and eliminate all enforcement of const
>whatsoever.)

It is, however, a reason why eliminating limited but still-useful
feature X is not a big deal if something else is gained thereby.

As an example of a similar phenomenon in a different domain, consider
an office building with several entrance doors in a row.  Locking
one of those doors makes the building slightly more secure, for
various reasons.  However, the gain in security is small compared
to the gain from locking all the doors.

Eliminating unsigned long because we lack support for long long
would be like removing a working door from an office building because
there is not enough room to build another door.

--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/10/08
Raw View
David R Tribble <david@tribble.com> writes:

[...]

| You seem to be assuming that the following is less likely to be
| written "accidentally" because a reference is used instead of a
| pointer:
|
|     void foo(const Type &t)
|     {
|         ...
|         delete &t;
|     }
|
| I wouldn't make that assumption.


Following that logic, I'd conclude that

 delete const_cast<T*>(p);

can be written accidentally.

deletion *is* a perilous operation and everybody thinks or should
think about it more than once.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/08
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>Nathan Myers <ncm@nospam.cantrip.org> wrote:
>
>>That the language lacked potentially useful feature X' is not a
>>sensible reason to eliminate limited but still-useful feature X.
>>(The same reasoning would eliminate unsigned long because we lack
>>support for long long -- and eliminate all enforcement of const
>>whatsoever.)
>
>It is, however, a reason why eliminating limited but still-useful
>feature X is not a big deal if something else is gained thereby.

No such gain has been demonstrated.  Every example posted of a
supposed gain has been demonstrated to have been available in
the language already.

>As an example of a similar phenomenon in a different domain, consider
>an office building with several entrance doors in a row.  Locking
>one of those doors makes the building slightly more secure, for
>various reasons.  However, the gain in security is small compared
>to the gain from locking all the doors.

Interesting analogy.  Before the change, all the doors were locked.
Changing const semantics only for delete is equivalent to unlocking
one of the doors.  The same arguments for unlocking the one door
apply to all the doors.  Why lock any of them, now?  Nobody is kept
out, any more.  Const is now useless as a tool to describe or enforce
interface invariants where pointers are involved.

>Eliminating unsigned long because we lack support for long long
>would be like removing a working door from an office building because
>there is not enough room to build another door.

Exactly, a silly reason.  But that's what was argued.

I suspect that one source of disagreement arises from the fact
that const has become overloaded in C++.  In C it had only one
role, as a tool to describe and enforce interfaces.  In C++ it
acquired a role in advising the optimizer.

That latter role conflicts in some cases with the former.
People who are more interested in optimizations than in system
architecture have systematically favored compromising its role
in specifying and enforcing interfaces, wherever there is such
conflict.  It has now become so compromised as to be practically
useless for its original purpose.

Why those who favor using const solely to direct the optimizer,
and chafe at restrictions intended to help enforce interface
specifications, feel they must invent one logically-invalid
argument after another for breaking down its original role is
a mystery.  Why not just announce "interface specification is
not a valid role for the type system" and argue for eliminating
all enforcement of const restrictions on that basis?  After all,
const restrictions are still annoying in lots of other areas.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/10/05
Raw View
ncm@nospam.cantrip.org (Nathan Myers) writes:

[...]

|
| You don't need "foo":
|
|   void baz() { const int bar; }
|
| The presence of the explicit destructor can only confuse you.
| This is about deletion, not destructors.

The issue is that you can't ignore destruction.  Did you ever try to
ask yourself why people are concerned with destruction when they're
talking about deletion?  It just might be the case they use a
delete-expression to express an object destruction as they leave a
scope to end an auto object life.

[...]

| No, there is an enormous difference: the presence of a syntactic
| element, the *delete-expression*.  It appears nowhere in the first
| example, it is central in the second.  The example, furthermore,
| is misleading, because the destruction in the first case is
| lexically coupled to the creation, construction, and lifetime
| of the object, but the deletion need not be.  (That they are
| adjacent in the example is purely an accident of brevity; this
| accident is what makes the example misleading.)

Sorry, but although I agree with your first two sentences -- which are
just a statement of the obvious -- I don't follow your conclusion that
the example is misleading.  Alexandre's example illustratres a use of
delete-expression: detroying an object on heap and release occupied
memory.  His main point is to make a parallel with the case of a const
auto object.

[...]

| In fact, the destructor always could be run on the dynamic object,
| by use of appropriate language constructs:
|
| >  void buz() { delete const_cast<foo*>(new const foo); }
|
| You cannot insert a const_cast accidentally, so lifetime errors
| from deleting "the wrong thing" were correspondingly harder.

You cannot delete a pointer (to-const or not) accidently.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr


[ 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: Jonathan.Coxhead@sv.sc.philips.com (Jonathan R. Coxhead)
Date: 1999/10/05
Raw View
   ncm@nospam.cantrip.org (Nathan Myers) writes:

 | Jonathan Coxhead <Jonathan.Coxhead@sv.sc.philips.com> wrote:
 | >
 | >   Here's an argument I find utterly convincing:
 | >
 | >********************************************************************
 | >   If it is allowed to create and construct const objects, it is
 | >logically necessary to allow them to be destroyed and deleted.
 | >********************************************************************
 | >
 | >   How else could they ever be disposed of?
 |
 | The above merely restates the original, fallacious argument.
 |
 | Objects were being disposed of nicely before the meaning of const was
 | changed, and they are being disposed of nicely afterward. The change
 | to const semantics did not affect this. Therefore, the argument above
 | does not actually support a change.

   It isn't an argument for change, but for the status quo.

 | This logical fallacy underlies the problems in several of the
 | arguments, such as that containers of "const T" should be possible
 | (they always have been) or that STL Containers of "const T" should be
 | possible (they still aren't).

   You haven't shown the logical flaw in the above, though: you've
merely stated that it exists. Maybe you could expand on the fundamental
difference between creation and deletion which causes one of them to be
valid for const objects (without casting or other asymmetrical warts),
but not the other?

 | Incidentally, the issue is entirely about "deletion", not
 | "destruction". They are not the same thing.

   ... which is why I mentioned them separately.

        /|
 o o o (_|/
        /|
       (_/
---
[ 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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/10/05
Raw View
>> Really? How, then, is one supposed to use std::istream::read() and
>> std::ostream::write() for anything other than const char* buffers without
>> writing dubious code?

[ humorous passage snipped...]

>Seriously, I would have designed write and read w/ void*
>interfaces. (But I am not the one who designed iostream
>-- otherwise, it would be better ;-)

So would I and I have said so publicly and been rebuffed in a letter to the
editor from a committee member for doing so.
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/10/07
Raw View
In article <org0zokcui.fsf@cupuacu.lsd.ic.unicamp.br>, Alexandre Oliva
<oliva@lsd.ic.unicamp.br> writes
>Now you're talking about safety of `delete', which is a completely
>different issue, IMHO.  If you want safety from deleting the wrong
>object, you have to go for garbage collection or something like that;
>new/delete just can't get you there.

BTW, if you want safety from 'accidental' delete why are you not passing
by reference?

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/07
Raw View
Alexandre Oliva  <oliva@lsd.ic.unicamp.br> wrote:
>On Oct  4, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:
>
>>> void buz() { delete const_cast<foo*>(new const foo); }
>
>> You cannot insert a const_cast accidentally, so lifetime errors
>> from deleting "the wrong thing" were correspondingly harder.
>> That protection is gone now.
>
>Now you're talking about safety of `delete', which is a completely
>different issue, IMHO.

The _only_ aspect of const semantics that was changed was how (whether)
it applied to delete-expressions.  Anything else would be a different
issue.

>If you want safety from deleting the wrong
>object, you have to go for garbage collection or something like that;
>new/delete just can't get you there.

Garbage collection can't "get you there" either.   The point was
to allow code to pass around pointers -- not necessarily to dynamic
storage -- and be assured that nothing would damage them.  It did
work for that, but no longer does.

>Arguing that `const' should protect against `delete' is arguing for
>breaking the very orthogonality between deletion and destruction.

Const _never_ protected against destruction.  It protected against
improper deletion -- and assignment.

Any argument that it was not useful to protect against improper
deletion needs to be accompanied by an explanation why it was
nonetheless useful for assignment.  All the arguments so far have
applied equally well in favor of eliminating restrictions on both
assignment and deletion.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Alexandre Oliva <oliva@lsd.ic.unicamp.br>
Date: 1999/10/08
Raw View
On Oct  7, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:

> Alexandre Oliva  <oliva@lsd.ic.unicamp.br> wrote:
>> On Oct  4, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:
>>
>>>> void buz() { delete const_cast<foo*>(new const foo); }
>>
>>> You cannot insert a const_cast accidentally, so lifetime errors
>>> from deleting "the wrong thing" were correspondingly harder.
>>> That protection is gone now.
>>
>> Now you're talking about safety of `delete', which is a completely
>> different issue, IMHO.

> The _only_ aspect of const semantics that was changed was how (whether)
> it applied to delete-expressions.  Anything else would be a different
> issue.

I meant that delete const isn't the only unsafe aspect of delete.
There are so many others that I don't think there's anything so
special about this one that it deserves so much attention.  I prefer
to consider plain pointers unsafe at best, and, if you need any
protection, you need some kind of smart pointer.

> The point was to allow code to pass around pointers -- not
> necessarily to dynamic storage -- and be assured that nothing would
> damage them.  It did work for that, but no longer does.

It didn't, because:

> Const _never_ protected against destruction.  It protected against
> improper deletion -- and assignment.

Since someone (for example, the template function `foo' below) could
still invoke the destructor for the object pointed by the pointer you
gave them, even if the pointer was to a const-qualified version of the
object's type, there's no guarantee that the object won't be messed up
with.  Therefore the whole discussion is pointless.

One proposal that would lead to some advance in the direction you
want, namely, to be able to have a pointer to a const object that
can't be used to modify the object in any way (except, of course, by
casting away constness or invoking undefined behavior with type
punning or direct memory access), is by specifying that:

- neither constructors nor destructors can be invoked for const types

- when initializing and destructing automatic, namespace-scope and
  local-static objects and static data members, their cv-qualifiers
  are disregarded

- the cv-qualifiers of a non-static data member are disregarded for
  the implicit invocation of its constructor from a constructor of the
  containing class, and for the implicit invocation of its destructor
  from a destructor of the containing class.

Have I missed any case of well-formed con/destruction of const?

Note that the wording above renders the following constructs
ill-formed:

template <typename T> void foo(T const *p) {
  p->~T(); // error, cannot destruct const object
  new (p) T; // already invalid, casting p to void* discards const
  p = new const T; // error, cannot construct const object
  delete p; // error, cannot destruct const object
}

IMHO, prohibiting deletion of const without prohibiting destruction of
const is pointless.  The exceptions in the wording above sound (to me)
much more natural than the exception on delete of const.  Ruling away
delete of const sounds arbitrary and doesn't accomplish the intended
benefit, while the exceptions for constness violations at construction
and destruction time already exist and are necessary for const to be
usable.

Nevertheless, ruling away construction and deletion of cv-qualified
types would cause a lot of inconvenience for template code that must
deal with allocators and explicit invocation of constructors and
destructors.  As I wrote before, this can be worked around by using
traits classes with specializations for cv-qualified types that
discard the cv-qualifiers:

template <typename T> struct cv_unqualified
{ typedef T type; };
template <typename T> struct cv_unqualified<const T>
{ typedef T type; };
template <typename T> struct cv_unqualified<volatile T>
{ typedef T type; };
template <typename T> struct cv_unqualified<const volatile T>
{ typedef T type; };

Such a template and its specializations should probably be made part
of the Standard should construction and destruction of cv-qualified
types be ruled out.  Then, a template function like `foo' above could
be rewritten so as to work even for cv-qualified T as below:

template <typename T>
void foo(T /*const*/ *p) { // assume deduced const
  typedef typename cv_unqualified<T>::type Tu;
  const_cast<Tu *>(p)->~Tu();
  new (const_cast<void*>(p)) Tu;
  p = new Tu;
  delete const_cast<Tu *>(p);
}


It doesn't even look that bad.  But it would require a lot of code to
be rewritten :-(

--
Alexandre Oliva http://www.ic.unicamp.br/~oliva IC-Unicamp, Bra[sz]il
oliva@{lsd.ic.unicamp.br,guarana.{org,com}} aoliva@{acm,computer}.org
oliva@{gnu.org,kaffe.org,{egcs,sourceware}.cygnus.com,samba.org}
** I may forward mail about projects to mailing lists; please use them


[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/10/08
Raw View
In article <37fcedaa$0$215@nntp1.ba.best.com>,
Nathan Myers <ncm@nospam.cantrip.org> wrote:

>Any argument that it was not useful to protect against improper
>deletion needs to be accompanied by an explanation why it was
>nonetheless useful for assignment.  All the arguments so far have
>applied equally well in favor of eliminating restrictions on both
>assignment and deletion.

Every object of a given type supports assignment in exactly the
same way, but not every object of a given type supports deletion
in the same way.  So, for example, if p and q point to objects
of type t, the validity of executing   *p = q   does not depend
on the particular objects to which p and q point.  In contrast,
whether or not   delete p   is valid depends on the particular object
to which p points.

The ability to assign to an object is part of the object's type.
The ability to delete an object depends on the object's identity
as well.  Therefore assignment and deletion are fundamentally
different, and it is legitimate to explore how those differences
should be expressed as part of the language design.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: David R Tribble <david@tribble.com>
Date: 1999/10/05
Raw View
Francis Glassborow wrote:
>> I would strongly favour the next version of the C++ standard (or
>> even via a corrigendum) providing another qualifier ['no_delete']
>> to inhibit destruction.

Christopher Eltschka wrote:
> The "nodelete" modifier in the "no delete for const"
> case would be a sort of "weaker const", just as "protected"
> is a sort of "weaker private". That is, it would not be a
> separate attribute, but an additional protection level
> in the const range, between const and non-const.

Some of us wish that C++ would disallow deletion of const objects,
e.g.:

    void xyzzy(const Type *p)
    {
        delete p;          // should be an error
    }

Perhaps we could modify the class declaration syntax to allow two
destructors in a class declaration, one declared as const and one
declared as non-const, and allow them to have different access
privileges:

    class Bar
    {
    public:
        ~Bar();             // old syntax, new meaning:
                            // only called for non-const objects

    protected:
        ~Bar() const;       // new syntax,
                            // only called for const objects
    };

    void xyz(const Bar *b)
    {
        delete b;                      // error, no access
                                       // to Bar::~Bar() const

        delete const_cast<Bar *>(b);   // okay,
                                       // calls Bar::~Bar()
    }

This proposal has the advantage that it does not break existing
code.  It is also a fairly small change to the grammar.

It has the disadvantage that a class could now have two different
destructor functions, which are called depending on whether the
object is const or not.  OTOH, this could be considered as an
advantage (i.e., perhaps destruction of a const object requires
different actions to be performed by the dtor).  Presumably, most
const dtors could simply invoke the non-const dtor (or visa versa):

    Bar::~Bar() const
    {
        const_cast<Bar *>(this)->~Bar();
    }

We still have to figure out if the following is valid or not, though:

    void aaa()
    {
        const Bar   o;

        // o.~Bar()const called here or not?
    }

-- David R. Tribble, david@tribble.com, http://www.david.tribble.com --


[ 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: Jerry Leichter <jerrold.leichter@smarts.com>
Date: 1999/10/05
Raw View
| Here's an example I just thought of.
|
|    void f(const int& i) {
|       i++;    }
|
| The above function is an error because it tries to modify a const
| object.
|
| No problem.  Here's a workaround that works in standard C++.
|
|    void f(const int& i) {
|       int ii=i+1;
|       i.~int();
|       new (i) int(ii);
 new (&i) int(ii), presumably
|    }
|
| In the interests of safety, the above program should not compile.

As Hyman Rosen pointed out (and I mentioned in a previous discussion),
this won't compile:  Placement new needs a void*, but &i is a const int*
so a const_cast is required.

Consider the peculiar logic of the Standard as now written:  Given a
const T*, you can destroy what's in there, logically reducing it to a
bag of random bits.  But given a bag of random bits, you are *not*
allowed to use a const void* to build data atop it.  Somehow, those
random bits are more worthy of protection than real information....

       -- Jerry
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/05
Raw View
Jonathan R. Coxhead <Jonathan.Coxhead@sv.sc.philips.com> wrote:
>   ncm@nospam.cantrip.org (Nathan Myers) writes:
> | Jonathan Coxhead <Jonathan.Coxhead@sv.sc.philips.com> wrote:
> | >If it is allowed to create and construct const objects, it is
> | >logically necessary to allow them to be destroyed and deleted.
> | >   How else could they ever be disposed of?
> |
> | The above merely restates the original, fallacious argument.
> |
> | Objects were being disposed of nicely before the meaning of const was
> | changed, and they are being disposed of nicely afterward. The change
> | to const semantics did not affect this. Therefore, the argument above
> | does not actually support a change.
>
>   It isn't an argument for change, but for the status quo.

Jonathan, please try to pay attention.  There really was a change, and
you really are trying (and failing, at it happens) to argue in support
of the change.

> | This logical fallacy underlies the problems in several of the
> | arguments, such as that containers of "const T" should be possible
> | (they always have been) or that STL Containers of "const T" should be
> | possible (they still aren't).
>
>   You haven't shown the logical flaw in the above, though: you've
>merely stated that it exists. Maybe you could expand on the fundamental
>difference between creation and deletion which causes one of them to be
>valid for const objects (without casting or other asymmetrical warts),
>but not the other?

Maybe you will understand better by example.

My little niece will try to persuade you to get your tonsils
removed.  Her argument is that you can have all the ice cream
you want afterward.  Yet, you can have all the ice cream you
want already.  None of this has anything to do with any merits of
having your tonsils removed, just as your assertion has nothing to
do with any merits of the change to const semantics.

In response to your other question, somebody else already pointed out:
creation is a class operation, where destruction is an object operation.
Symmetry arguments may be fun, but they can't help decide anything
if they ignore actual consequences -- or assert false symmetries.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/10/06
Raw View
David R Tribble wrote:
>
> Francis Glassborow wrote:
> >> I would strongly favour the next version of the C++ standard (or
> >> even via a corrigendum) providing another qualifier ['no_delete']
> >> to inhibit destruction.
>
> Christopher Eltschka wrote:
> > The "nodelete" modifier in the "no delete for const"
> > case would be a sort of "weaker const", just as "protected"
> > is a sort of "weaker private". That is, it would not be a
> > separate attribute, but an additional protection level
> > in the const range, between const and non-const.
>
> Some of us wish that C++ would disallow deletion of const objects,
> e.g.:
>
>     void xyzzy(const Type *p)
>     {
>         delete p;          // should be an error
>     }

Yes, this is what the whole thread is about ;-)

The point is that some also want a way to prevent deletion of
pointers, i.e. no_delete. It has been argued that with the
"no-const-delete" rule, a meaningful no_delete would not be
possible. My point was that it would be possible if it were
done as an additional protection level in the "const" range,
instead of an independant attribute.

>
> Perhaps we could modify the class declaration syntax to allow two
> destructors in a class declaration, one declared as const and one
> declared as non-const, and allow them to have different access
> privileges:
>
>     class Bar
>     {
>     public:
>         ~Bar();             // old syntax, new meaning:
>                             // only called for non-const objects
>
>     protected:
>         ~Bar() const;       // new syntax,
>                             // only called for const objects
>     };
>
>     void xyz(const Bar *b)
>     {
>         delete b;                      // error, no access
>                                        // to Bar::~Bar() const
>
>         delete const_cast<Bar *>(b);   // okay,
>                                        // calls Bar::~Bar()
>     }
>
> This proposal has the advantage that it does not break existing
> code.  It is also a fairly small change to the grammar.

But it's counter-intuitive, in that the non-const version
may be called even on const objects, if the const version
is not provided. OTOH one could say the compiler
automatically provides the const version if no one is
declared, and that automatic const version just calls the
non-const one.

A bigger problem is that since protection is also checked
for automatic objects, this would also prevent the following:

void foo()
{
  Bar const foobar;
} // Error: const destructor is not accessible

Therefore adding a protected or private const destructor
to an existing class would break all non-dynamic constant
objects of that class.

>
> It has the disadvantage that a class could now have two different
> destructor functions, which are called depending on whether the
> object is const or not.  OTOH, this could be considered as an
> advantage (i.e., perhaps destruction of a const object requires
> different actions to be performed by the dtor).  Presumably, most
> const dtors could simply invoke the non-const dtor (or visa versa):
>
>     Bar::~Bar() const
>     {
>         const_cast<Bar *>(this)->~Bar();
>     }

If you don't want to prevent the call, and don't want to do
something different, then you would not provide the const
destructor - the non-const version would be called instead
(needed for compatibility with current code).

Also note that your code is (would be) invalid: All members
and base classes would be destructed twice, once for the
directly invoked destructor, and again after Bar::~Bar() const
returns (since this is how destructors work).
A compiler generated destructor could do it, however, since
it would know that it may not run the destructors again.


However note that the destructor called does _not_ depend
on the constness of the object, but on the constness of
the access path, which might be a problem:

void foo2()
{
  Bar* p1 = new Bar;
  Bar* p2 = new Bar;
  Bar const* p3 = p2;

  delete p1; // calls Bar::~Bar()
  delete p3; // calls Bar::~Bar() const
}

That is, for a non-const object, you wouldn't be able to
predict which destructor will be called unless you know
which access path is used to delete it:

void destroy(Bar* p);
// will this use the const- or non-const destructor?

>
> We still have to figure out if the following is valid or not, though:
>
>     void aaa()
>     {
>         const Bar   o;
>
>         // o.~Bar()const called here or not?
>     }

This code would be invalid, as noted above.

To sum up:
- The semantics is not the same as normally for const/non-const
  overload (but that could be fixed with an additional
  "implicit defined"-rule)
- The "protected const destructor" trick would make static and
  automatic objects of that class impossible
- If both destructors are defined, the version which was called
  depends on the constness of the current access path, not on
  that of the object itself (otherwise the protected const
  destructor trick wouldn't work)

In short: Too many problems IMHO.


[ 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: Alexandre Oliva <oliva@lsd.ic.unicamp.br>
Date: 1999/10/07
Raw View
On Oct  4, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:

>> void buz() { delete const_cast<foo*>(new const foo); }

> You cannot insert a const_cast accidentally, so lifetime errors
> from deleting "the wrong thing" were correspondingly harder.
> That protection is gone now.

Now you're talking about safety of `delete', which is a completely
different issue, IMHO.  If you want safety from deleting the wrong
object, you have to go for garbage collection or something like that;
new/delete just can't get you there.

Arguing that `const' should protect against `delete' is arguing for
breaking the very orthogonality between deletion and destruction.

--
Alexandre Oliva http://www.ic.unicamp.br/~oliva IC-Unicamp, Bra[sz]il
oliva@{lsd.ic.unicamp.br,guarana.{org,com}} aoliva@{acm,computer}.org
oliva@{gnu.org,kaffe.org,{egcs,sourceware}.cygnus.com,samba.org}
** I may forward mail about projects to mailing lists; please use them
---
[ 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: James Kuyper <kuyper@wizard.net>
Date: 1999/10/04
Raw View
Nathan Myers wrote:
>
> Siemel B. Naran <sbnaran@uiuc.edu> wrote:
> > Logically speaking, at the
> >"delete ptr", the object pointed to by 'ptr' no longer exists and
> >so it matters not whether the object is const or not.
>
> Sorry, Siemel, you have just committed "Exhibit A".  (Pray your
> professor's not reading this.)
>
>   JUDGE: You're charged with murder, do you have anything to say?
>   CROOK: It's no murder to shoot a corpse.
>   JUDGE: You're saying he was already dead?!
>   CROOK: He was after I shot him.  Anyway I don't hear him complaining.

An analogy that is closer to the argument actually being used:

JUDGE: You're charged with violating your employment offer, guaranteeing
the plaintiff a particular assignment - do you have anything to say?
DEFENDANT: It's no crime not to assign any tasks to someone who isn't
your employee.
JUDGE: You're saying he wasn't your employee?
DEFENDANT: He wasn't after I fired him.

In this analogy, your disagreement about 'const' corresponds to a
disagreement about what a 'guaranteed assignment' clause in an
employement offer would means: does it mean only that the employee is
guaranteed not be reassigned, or does it also mean he's guaranteed not
be fired? If I had an employment offer with such a clause in it, I'd
probably need to check with a lawyer to know for sure. There's nothing
intrinsically illogical about either interpretation, though one is more
likely than the other.

The analogy is poor, because 'const' is much more common in C++ code (at
least in my experience), than guaranteed assignments in employement
offers. Sorry - it was the best I could do.
---
[ 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: Alexandre Oliva <oliva@lsd.ic.unicamp.br>
Date: 1999/10/04
Raw View
On Oct  4, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:

> Jonathan R. Coxhead <Jonathan.Coxhead@sv.sc.philips.com> wrote:

>> If it is allowed to create and construct const objects, it is
>> logically necessary to allow them to be destroyed and deleted.

> Objects were being disposed of nicely before the meaning of const
> was changed, and they are being disposed of nicely afterward.  The
> change to const semantics did not affect this.

Assume:

struct foo { foo(); ~foo(); };

void baz() { const foo bar; }

Even though `bar' is const, its destructor can (and must) be executed,
possibly modifying it before its life terminates.

Now think of:

void buz() { delete new const foo; }

What's the difference between this and the former example?  Just that,
in the former case, the instance of `foo' was allocated from the
stack, and, in the latter case, it was allocated from the heap.  In
both cases, raw storage was obtained, the constructor was executed to
turn the raw storage into a const object, the destructor was run on
the const object turning it back into raw storage that was finally
disposed of.

If the destructor can be run on a const object in `baz', why couldn't
it in `buz'?

--
Alexandre Oliva http://www.ic.unicamp.br/~oliva IC-Unicamp, Bra[sz]il
oliva@{lsd.ic.unicamp.br,guarana.{org,com}} aoliva@{acm,computer}.org
oliva@{gnu.org,kaffe.org,{egcs,sourceware}.cygnus.com,samba.org}
** I may forward mail about projects to mailing lists; please use them
---
[ 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: Hyman Rosen <hymie@prolifics.com>
Date: 1999/10/04
Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
> No problem.  Here's a workaround that works in standard C++.
>    void f(const int& i) {
>       int ii=i+1;
>       i.~int();
>       new (i) int(ii);
>    }
> In the interests of safety, the above program should not compile.

And it doesn't. At the very least, you would need to say

 new (const_cast<int *>(&i)) int(ii);

And if i is a reference to an actual const object, the program is
undefined, by 3.8/9.


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/04
Raw View
James Kuyper  <kuyper@wizard.net> wrote:
>Nathan Myers wrote:
>>
>> Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>> > Logically speaking, at the
>> >"delete ptr", the object pointed to by 'ptr' no longer exists and
>> >so it matters not whether the object is const or not.
>>
>> Sorry, Siemel, you have just committed "Exhibit A".  (Pray your
>> professor's not reading this.)
>>
>>   JUDGE: You're charged with murder, do you have anything to say?
>>   CROOK: It's no murder to shoot a corpse.
>>   JUDGE: You're saying he was already dead?!
>>   CROOK: He was after I shot him.  Anyway I don't hear him complaining.
>
>An analogy that is closer to the argument actually being used:
>
>JUDGE: You're charged with violating your employment offer, guaranteeing
>the plaintiff a particular assignment - do you have anything to say?
>DEFENDANT: It's no crime not to assign any tasks to someone who isn't
>your employee.
>JUDGE: You're saying he wasn't your employee?
>DEFENDANT: He wasn't after I fired him.

Sorry, James, you have missed the whole point.   In your analogy,
deletion corresponds to the firing, not to assignments, and the entire
issue is whether the employer had the right to fire him.  That is
determined by what it says in the contract, and the vote in committee
was, in effect, on what it should say in the contract.

Siemel's quote above is the logical equivalent of plugging a power
strip back into itself and expecting the lights to come on.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/04
Raw View
Alexandre Oliva  <oliva@lsd.ic.unicamp.br> wrote:
>On Oct  4, 1999, ncm@nospam.cantrip.org (Nathan Myers) wrote:
>> Jonathan R. Coxhead <Jonathan.Coxhead@sv.sc.philips.com> wrote:
>
>>> If it is allowed to create and construct const objects, it is
>>> logically necessary to allow them to be destroyed and deleted.
>
>> Objects were being disposed of nicely before the meaning of const
>> was changed, and they are being disposed of nicely afterward.  The
>> change to const semantics did not affect this.
>
>Assume:
>
>  struct foo { foo(); ~foo(); };
>  void baz() { const foo bar; }
>
>Even though `bar' is const, its destructor can (and must) be executed,
>possibly modifying it before its life terminates.

You don't need "foo":

  void baz() { const int bar; }

The presence of the explicit destructor can only confuse you.
This is about deletion, not destructors.

>Now think of:
>
>  void buz() { delete new const foo; }

or

  void buz() { delete new const int; }

>What's the difference between this and the former example?  Just that,
>in the former case, the instance of `foo' was allocated from the
>stack, and, in the latter case, it was allocated from the heap.

No, there is an enormous difference: the presence of a syntactic
element, the *delete-expression*.  It appears nowhere in the first
example, it is central in the second.  The example, furthermore,
is misleading, because the destruction in the first case is
lexically coupled to the creation, construction, and lifetime
of the object, but the deletion need not be.  (That they are
adjacent in the example is purely an accident of brevity; this
accident is what makes the example misleading.)

The decoupling of lifetime from lexical structure makes deletion more
dangerous than lexical destruction, and justifies greater care.  In the
past the language assisted with exercising that care.  Now the best
we can do is compiler warnings.

>In both cases, raw storage was obtained, the constructor was executed
>to turn the raw storage into a const object, the destructor was run on
>the const object turning it back into raw storage that was finally
>disposed of.
>
>If the destructor can be run on a const object in `baz', why couldn't
>it in `buz'?

There is no restriction whatsoever on running the destructor.
The topic is restrictions on the delete-expression applied to a
pointer-to-const, which doesn't appear at all in the other example.

In fact, the destructor always could be run on the dynamic object,
by use of appropriate language constructs:

>  void buz() { delete const_cast<foo*>(new const foo); }

You cannot insert a const_cast accidentally, so lifetime errors
from deleting "the wrong thing" were correspondingly harder.
That protection is gone now.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/10/05
Raw View
Al Stevens wrote:

> Andrei Alexandrescu wrote in message <7svnoq$udn$1@nnrp1.deja.com>...
>
> >The main debate is what's the default behavior. A program that uses any
> >cast (except dynamic_cast) risks undefined behavior and is dubious to
> >say the least, and anyone knows that.
>
> Really? How, then, is one supposed to use std::istream::read() and
> std::ostream::write() for anything other than const char* buffers without
> writing dubious code?

Some would that writing a file on disk which can only
be read on the same machine w/ a program compiled w/
the same compiler w/ the same options is dubious.

Seriously, I would have designed write and read w/ void*
interfaces. (But I am not the one who designed iostream
-- otherwise, it would be better ;-)

[BTW, the standard has a defect in that it doesn't
*say* that reinterpret_cast<char*> (&anything) *is*
portable -- although we all know that.]

--

Valentin Bonnard
---
[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/03
Raw View
On 1 Oct 1999 21:48:28 GMT, Jonathan R. Coxhead

>   Here's an argument I find utterly convincing:
>
>************************************************************************
>   If it is allowed to create and construct const objects, it is
>logically necessary to allow them to be destroyed and deleted.
>************************************************************************
>
>   How else could they ever be disposed of?
>
>   So the the C standard is correct, and the counterarguments are
>confused.
>
>   Does that end the debate?

The question is not one of logic alone.  Logically speaking, at the
"delete ptr", the object pointed to by 'ptr' no longer exists and
so it matters not whether the object is const or not.  But in
practice, one may have a really const object, or maybe an object
that we only what others to look at and not manipulate in any way.
That's where the rule that you cannot delete a pointer to const
helps us -- it gives us just 0.01% more safety.


>   As if ...

:).

--
--------------
siemel b naran
--------------
---
[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/03
Raw View
On 1 Oct 1999 21:48:28 GMT, Jonathan R. Coxhead

>   Here's an argument I find utterly convincing:
>
>************************************************************************
>   If it is allowed to create and construct const objects, it is
>logically necessary to allow them to be destroyed and deleted.
>************************************************************************

Here's an example I just thought of.

   void f(const int& i) {
      i++;
   }

The above function is an error because it tries to modify a const
object.



No problem.  Here's a workaround that works in standard C++.

   void f(const int& i) {
      int ii=i+1;
      i.~int();
      new (i) int(ii);
   }

In the interests of safety, the above program should not compile.

--
--------------
siemel b naran
--------------
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/10/03
Raw View
In article <slrn7vacco.k65.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>On 01 Oct 99 18:07:51 GMT, Andrei Alexandrescu <andrewalex@hotmail.com> wrote:
>
>>The main debate is what's the default behavior. A program that uses any
>>cast (except dynamic_cast) risks undefined behavior and is dubious to
>>say the least, and anyone knows that.
>
>Indeed, in code reviews the phrase "something_cast<...>(...)" always
>stands out.  This puts us in alert mode, and in our review, we tend to
>read the code more carefully.  And deleting a constant thing (ie,
>deleting a pointer to const) is something that should stand out in
>code reviews, and so we should have to use "const_cast".

While I accept the premise, I would want all delete's of non-local
objects to stand out.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/10/03
Raw View
Siemel B. Naran wrote:

> On 29 Sep 99 19:37:29 GMT, Andrew Koenig <ark@research.att.com> wrote:

> >               void g(a* ap);
> >
> >               a* ap = new a(1, 2, 3);
> >               f(ap);
> >               delete ap;

> Is the above example really that common?

> I almost never write code
> like the above.  What do others say?

You never use by-name arguments so that functions may
change them, as in:

   void mutliplies_by_2 (int& i);

or

   void mutliplies_by_2 (int* i);

I find that interresting.

--

Valentin Bonnard
---
[ 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: James Dennett <jdennett@acm.org>
Date: 1999/10/04
Raw View
Dave Harris wrote:

> jdennett@acm.org (James Dennett) wrote:
> > const Widget *cw(Factory.NewWidget("Fred",123));
> > ... // code using cw
> > delete cw;
> >
> > What style of code would you recommend here?
>
> This has been discussed many times in this forum. If the ARM rule hadn't
> been changed, you should use a template class similar to std::auto_ptr,
> which wraps a non-const argument and exposed it as const.

Thanks -- I must have slept through the previous discussions.  I'll use your
suggested approach.  The factory should return a const_auto_ptr<Widget>
(where const_auto_ptr is as you suggest).  The fact that I can write code
such as "delete cw.get();" in that case is not a problem -- folk surely
don't just go throwing "delete" in front of expressions which they don't
own.

Hopefully there's scope for us to work on adding some more standard smart
pointer templates to the C++ Standard next time around.  A version of
std::auto_ptr which only gives out const pointers shouldn't be hard to
specify.

-- James Dennett <jdennett@acm.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              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/10/04
Raw View
Andrei Alexandrescu wrote in message <7svnoq$udn$1@nnrp1.deja.com>...

>The main debate is what's the default behavior. A program that uses any
>cast (except dynamic_cast) risks undefined behavior and is dubious to
>say the least, and anyone knows that.


Really? How, then, is one supposed to use std::istream::read() and
std::ostream::write() for anything other than const char* buffers without
writing dubious 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/04
Raw View
Jonathan R. Coxhead <Jonathan.Coxhead@sv.sc.philips.com> wrote:
>   Here's an argument I find utterly convincing:
>
>************************************************************************
>   If it is allowed to create and construct const objects, it is
>logically necessary to allow them to be destroyed and deleted.
>************************************************************************
>
>   How else could they ever be disposed of?

The above merely restates the original, fallacious argument.

Objects were being disposed of nicely before the meaning of const
was changed, and they are being disposed of nicely afterward.  The
change to const semantics did not affect this.  Therefore, the argument
above does not actually support a change.

This logical fallacy underlies the problems in several of the arguments,
such as that containers of "const T" should be possible (they always
have been) or that STL Containers of "const T" should be possible
(they still aren't).

Incidentally, the issue is entirely about "deletion", not "destruction".
They are not the same thing.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/04
Raw View
Siemel B. Naran <sbnaran@uiuc.edu> wrote:
> Logically speaking, at the
>"delete ptr", the object pointed to by 'ptr' no longer exists and
>so it matters not whether the object is const or not.

Sorry, Siemel, you have just committed "Exhibit A".  (Pray your
professor's not reading this.)

  JUDGE: You're charged with murder, do you have anything to say?
  CROOK: It's no murder to shoot a corpse.
  JUDGE: You're saying he was already dead?!
  CROOK: He was after I shot him.  Anyway I don't hear him complaining.

I find it pretty surprising to see this kind of reasoning appear here,
and more surprising to find it in full session at the ISO meeting.
It seems worth studying why.  First, though, we need to acknowledge
that it actually is bad reasoning.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/10/04
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>Andrei Alexandrescu  <andrewalex@hotmail.com> wrote:
>
>>The main debate is what's the default behavior. A program that uses any
>>cast (except dynamic_cast) risks undefined behavior and is dubious to
>>say the least, and anyone knows that.
>
>I hope not, because it's not true.  There are plenty of casts that
>are well defined in all implementations.  In particular, casting
>a value of type T* to const T* and back is well defined in all
>implementations.

Andrei is not talking about implementations, he is talking about code.
Given a random pointer of unknown provenance, applying any but a few
specific casts risks undefined behavior.

Any code that uses a cast improperly -- i.e., without having
demonstrated its safety -- is at explicitly at fault; you cannot
"accidentally" insert a cast.

Therefore, a library can reasonably assume that its clients will
not apply casts to pointers it releases.  This is the basis for
treating constness and its language implications as part of an
interface specification.  A library designer could assume that
a pointer-to-const (accidentally) assigned through or deleted
would result in a compile-time error message.

While a released pointer-to-nonconst did not get the same protection
that a pointer-to-const did, and that may have been an omission in the
language, that did not weaken the usefulness of pointer-to-const in
interface design.  To release a pointer-to-nonconst safely a wrapper
class was needed.

Now, there is no protection for pointers, and designers must create
wrapper classes to get the same protection they once got from basic
language features.

>>My current opinion is that
>>ultimately "delete const" leads to worse programs, the only advantage
>>being marginally more elegant code in rare situations.
>
>I have always said that the counterarguments make sense.
>I just think that the arguments in favor of "delete const" are
>stronger.

So far Andrew has chosen not to point out any errors in the criticisms
of the latter  arguments, if in fact he can.

  - His "it should be possible to delete what you create" argument
    failed to support the change because it was possible before the
    change, and remains so.

  - His Unix file system analogy, for instance, when corrected to
    reflect actual conditions, failed to support the change, because
    Unix (like other garbage-collected systems) has no operation that
    corresponds to deletion.  ("rm" corresponds, precisely, to zeroing
    a pointer.)

  - His "containers of 'const T'" example failed to support the change,
    because they were equally possible before and after the change.

  - His "C++ lacks a general no-delete modifier" argument failed to
    support the change, because C++ still lacks a no-delete modifier.

Andrew is of course free to consider any argument convincing, valid or
not.  However, he has not explained why any of us should be persuaded
by them, in light of the enormous holes in each argument.  Nor has he
withdrawn them.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/10/01
Raw View
In article <FIsF3q.5IJ@research.att.com>,
  ark@research.att.com (Andrew Koenig) wrote:
[to Al Stevens]
> I almost agree with you.  There are only two problems:
>
>  1. The language offers no such guarantee, and never did, because
>     it has always been legal for f to use a cast to remove the
const
>     and then delete the object anyway.

Andrew, I hoped we could throw the argument involving casts. Casts can
be used to any end whatsoever. The function f can do pretty much
anything it wants with its argument, be it const or not, if casts can
be used.

The main debate is what's the default behavior. A program that uses any
cast (except dynamic_cast) risks undefined behavior and is dubious to
say the least, and anyone knows that.

I agree with your point #2 quoted (in fragment) below. However, I lean
towards thinking that it's a mistake that the ARM rules are changed.
The more I think of it, the more some of the counterarguments
to "delete const" make more sense to me. My current opinion is that
ultimately "delete const" leads to worse programs, the only advantage
being marginally more elegant code in rare situations.

I dare to say that I think even your opinion seems to have mildened a
bit.

>  2. Your example is much less common than the following:
>
>   void g(a* ap);
>
>   a* ap = new a(1, 2, 3);
>   f(ap);
>   delete ap;
>
>     Here, g cannot say "const" because it wants to modify the
object,
>     but it will not delete it.  How can we express in code that
g will
>     not delete the object?


Andrei


Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: Jonathan.Coxhead@sv.sc.philips.com (Jonathan R. Coxhead)
Date: 1999/10/01
Raw View
   ncm@nospam.cantrip.org (Nathan Myers) writes:

 | Andrew Koenig <ark@research.att.com> wrote:
 | >The real problem is that we have people on one side saying ``It's a
 | >judgment call'' and on the other side saying ``No it isn't -- I'm
 | >right and you're crazy.''
 |
 | _Everybody_, so far, has agreed that the const issue is a judgment
 | call. I don't think anybody but me has been called crazy.
 |
 | Repeating that it is a judgment call, though, doesn't lend any more
 | weight to one's choice than repeating logically-invalid arguments. If
 | one is to judge, it really should be based on sound engineering
 | analysis. I have seen Andrew and others involved in such analyses, so
 | I know they are capable of it. I just wonder what makes the activity
 | so unattractive in this particular case, and what makes the
 | logically-invalid arguments so attractive in its place.
 |
 | It would be puckish and perhaps invidious to suggest that it is
 | because sound engineering analysis doesn't produce the answer one
 | wants.

   Here's an argument I find utterly convincing:

************************************************************************
   If it is allowed to create and construct const objects, it is
logically necessary to allow them to be destroyed and deleted.
************************************************************************

   How else could they ever be disposed of?

   So the the C standard is correct, and the counterarguments are
confused.

   Does that end the debate?

   As if ...

        /|
 o o o (_|/
        /|
       (_/




[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/09/30
Raw View
jdennett@acm.org (James Dennett) wrote:
> const Widget *cw(Factory.NewWidget("Fred",123));
> ... // code using cw
> delete cw;
>
> What style of code would you recommend here?

This has been discussed many times in this forum. If the ARM rule hadn't
been changed, you should use a template class similar to std::auto_ptr,
which wraps a non-const argument and exposed it as const.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."
---
[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/10/01
Raw View
In article <37f3046c$0$203@nntp1.ba.best.com>,
Nathan Myers <ncm@nospam.cantrip.org> wrote:

>It would be puckish and perhaps invidious to suggest that it is because
>sound engineering analysis doesn't produce the answer one wants.

Well, no -- it would be absolutely correct to say that sound
analysis doesn't produce the answer that *you* want -- which
is why you persist in calling it unsound even though it isn't.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/01
Raw View
On 01 Oct 99 18:07:51 GMT, Andrei Alexandrescu <andrewalex@hotmail.com> wrote:

>The main debate is what's the default behavior. A program that uses any
>cast (except dynamic_cast) risks undefined behavior and is dubious to
>say the least, and anyone knows that.

Indeed, in code reviews the phrase "something_cast<...>(...)" always
stands out.  This puts us in alert mode, and in our review, we tend to
read the code more carefully.  And deleting a constant thing (ie,
deleting a pointer to const) is something that should stand out in
code reviews, and so we should have to use "const_cast".

--
--------------
siemel b naran
--------------


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/30
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>The real problem is that we have people on one side saying ``It's a
>judgment call'' and on the other side saying ``No it isn't -- I'm right
>and you're crazy.''

_Everybody_, so far, has agreed that the const issue is a judgment
call.  I don't think anybody but me has been called crazy.

Repeating that it is a judgment call, though, doesn't lend any
more weight to one's choice than repeating logically-invalid
arguments.  If one is to judge, it really should be based on sound
engineering analysis.  I have seen Andrew and others involved in
such analyses, so I know they are capable of it.  I just wonder what
makes the activity so unattractive in this particular case, and what
makes the logically-invalid arguments so attractive in its place.

It would be puckish and perhaps invidious to suggest that it is because
sound engineering analysis doesn't produce the answer one wants.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/09/30
Raw View
Nathan has repeatedly held forth that this discussion is not about the
technical issue, which was decided in committee and is cast in stone,  but
about the curious (in his opinion) phenomenon wherein people continue to
make specious (in his opinion) arguments after those arguments have been
demonstrated to be incorrect (in his opinion).

Inasmuch as Nathan did not originate the discussion, I do not think he can
rightfully lay claim to its subject (in my opinion).

The really curious thing about this thread is that it started to be about
deleting pointers to const, turned into being about the arguments advanced
about deleting pointers to const, and has now turned into being about
Nathan. What next?

[ moderator's note: Articles in this newsgroup are not supposed to
  be about individuals. Let's keep discussion about technical
  issues, please. -sdc ]


[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/30
Raw View
On 29 Sep 99 19:37:29 GMT, Andrew Koenig <ark@research.att.com> wrote:

> 2. Your example is much less common than the following:
>
>  void g(a* ap);
>
>  a* ap = new a(1, 2, 3);
>  f(ap);
>  delete ap;
>
>    Here, g cannot say "const" because it wants to modify the object,
>    but it will not delete it.  How can we express in code that g will
>    not delete the object?

Is the above example really that common?  Let's suppose that the object
pointed to by 'ap' is a private member of a bigger object.  This bigger
object likely has an integrity constraint -- for example, the 'ap'
object must be either an 'ap1' or 'ap2' or 'ap3', or the 'ap' object
and another 'aq' object must always be in sync.  But allowing function
g to modify 'ap' risks upsetting the integrity constraint.  Accordingly,
I think code like the above should be rare.  I almost never write code
like the above.  What do others say?

--
--------------
siemel b naran
--------------
---
[ 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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/09/30
Raw View
> Andrew Koenig wrote in message ...
> 1. The language offers no such guarantee, and never did, because
>    it has always been legal for f to use a cast to remove the const
>    and then delete the object anyway.

Legal, but bad form and requiring the conscious insertion of that cast by
the author of f, which says to all who see it, "I did this on purpose,"
assuming you can see it. The rule of yore at least discouraged the practice.

> How can we express in code that g will not delete the object?

I do not maintain that the prior rules were without their flaws, too. I
really think we flip-flopped the good and the bad here.

>In both cases, the only guarantee comes from the fact that you cannot
>legally delete an object that was not allocated by new, and f and g have no
>way of knowing that their arguments were obtained by new.

So I guess the object gets burned in f and g. (Sorry, musician's old, bad
pun.)

>The real problem is that we have people on one side saying ``It's a judgment
>call'' and on the other side saying ``No it isn't -- I'm right and you're crazy.''

Those are not the only two positions being taken here, although they have
dominated the discussion.

I agree that it was a judgement call. Having recently been the victim of a
moderator "judgement call" (the moderator's characterization), I also know
very well that judgement calls do not always reflect sound judgement. I just
don't think this one was well-enough thought out before positions were
taken, positions which now must be defended. That's the observation of an
outsider who does indeed see both sides of the issue and who can live with
the outcome.

Here's a passage that I find particularly interesting in view of the current
discussions.

"...they have never worked out what const really means. One of its intents
is to say that this is some data that can be put into some read-only storage
because it's never going to be modified. The definition that they have now
is sufficient for that. But they also had other ideas about what it should
mean, having to do with optimization, for example. The hope was that const
is somehow a promise that the compiler could assume that the data item
wouldn't change underfoot.

"If you have a pointer to a const, one might hope that what is const is not
going to suddenly change secretly. But, unfortunately, the way the rules
read that's not actually true. It can change, and this wasn't just an
oversight. In fact, they are potentially overloading the meaning of const.
There are ideas involved other than what people hoped to get, and they never
really worked out exactly which ones they wanted and which ones they didn't
want. It's a little confusing."




This is from an interview with Dennis Ritchie conducted 10 years ago while
the C standard was still underway and before the C++ committee convened.




[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/30
Raw View
In article <7stu29$nqt$1@engnews1.eng.sun.com>, Nathan Myers
<ncm@nospam.cantrip.org> writes
>
>Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
>>... Nathan keeps saying that ... what interests him is how
>>such sane and intelligent people could change the 'manifestly
>>correct' ARM position to the 'broken' ISO/ANSI C++ position.
>
>I would like it known that Francis Glassborow has repeatedly posted
>false and misleading "summaries" of my writings.
>
>Francis, I have asked you already not to put words in my mouth.
>Your characterization of my "interest" is entirely opposed to what
>I have explained here many, many times.  I have never mentioned,
>used, or even hinted at, the concept 'manifestly correct'.  The
>discussion was never about how the committee "could change" const;
>This discussion is about the quality of argumnets posted here.

Unless people feel able to summarise what they believe someone means it
is impossible to rebut them. You may think you have said something many
times, but the important thing is not what you said but what others
heard.

>
>Was this a troll?

I thought you knew me better.

>

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ 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: Ross Smith <ross.s@ihug.co.nz>
Date: 1999/09/30
Raw View
Francis Glassborow wrote:
>
> In article <7stu29$nqt$1@engnews1.eng.sun.com>, Nathan Myers
> <ncm@nospam.cantrip.org> writes
> >
> >Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
> >>... Nathan keeps saying that ... what interests him is how
> >>such sane and intelligent people could change the 'manifestly
> >>correct' ARM position to the 'broken' ISO/ANSI C++ position.
> >
> >I would like it known that Francis Glassborow has repeatedly posted
> >false and misleading "summaries" of my writings.
> >
> >Francis, I have asked you already not to put words in my mouth.
> >Your characterization of my "interest" is entirely opposed to what
> >I have explained here many, many times.  I have never mentioned,
> >used, or even hinted at, the concept 'manifestly correct'.  The
> >discussion was never about how the committee "could change" const;
> >This discussion is about the quality of argumnets posted here.
>
> Unless people feel able to summarise what they believe someone means it
> is impossible to rebut them. You may think you have said something many
> times, but the important thing is not what you said but what others
> heard.

Well, I think I've heard what Nathan's said fairly clearly, and it
doesn't bear any resemblance to the position Francis has attributed to
him.

I'm pretty neutral on the delete-const question; I lean mildly towards
the ARM rule but don't feel particularly strongly about it, so I think I
can claim to be a reasonably neutral observer. As I understand Nathan's
position, he has expressed no opinion on the question of "Should
deletion through pointer to const be allowed?" (or if he has, he's
clearly noted that it's irrelevant to his main argument). He is trying
to find out why people take (what he sees as) illogical arguments
seriously.

(I don't necessarily *agree* with Nathan's position that the arguments
are illogical, but I certainly do agree that he's made that position
perfectly clear.)

Conflating a claim that "this specific argument in favour of X is wrong"
with one that "X is wrong" is a fundamental error that I would have
thought anyone sufficiently competent at elementary logic to make a
living as a programmer would never make.

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
  "There are many technical details that make Linux attractive to the
  sort of people to whom technical details are attractive."   -- Suck


[ 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: James Dennett <jdennett@acm.org>
Date: 1999/09/30
Raw View
>
> I would be happy to see just a single logically-valid argument in
> favor of the change that occurred.  (I'm assuming, brightly, that such
> is possible.)  Failing that, I would be happy to see an acknowledgement
> from someone who favored the change that _any_one_ of the arguments
> presented repeatedly in support of the change was in fact logically
> invalid.  (I might propose the "it's ok to delete it because it already
> doesn't exist" one, if you don't know where to begin.)

I've not been defending deletion through const pointers, though I happen to
find it a reasonable practice.  What I want to ask is why the evidently
contradictory non-quote "it's ok to delete it because it already doesn't
exist" appears above.

The argument is:
1. A delete expression is a request to end the lifetime of an object which
currently exists.
2. The start of execution of the delete expression ends the "lifetime" of the
object.
3. After the delete expression's execution begins, the destructor is invoked
on what used to be an object.
  It would be perfectly reasonable, and indeed common, for the destructor to
leave behind a bunch of bytes which fail to satisfy the class invariant.  It's
not just another member function.
4. The bunch-of-bytes left after the destructor runs is returned to the
free-store.

So, replace the quote with "it's ok to reclaim the resources which were used
by the object [i.e., to invoke the destructor] because the object's lifetime
has been ended by the delete expression."

The counter-argument might be that *at the start of execution of the
destructor* the object is still "alive", and as such it would be fair to say
that it is "const".  If we consider that the object's lifetime has ended
before the destructor is invoked then there is no object to call "const".

If I tried to come up with a reason why I might possibly want to delete
through a const pointer, I might have code like the following:

// I don't need to change the Widget after its creation, so it's safest to
declare it as const.
const Widget *cw(Factory.NewWidget("Fred",123));
... // code using cw
delete cw;

Clearly I could omit the "const" but that loses the fact that I want cw to be
immutable during its lifetime.  I could cast away the const in the delete
expression, but casts are evil.  I can't just drop a Widget object on the
stack if I'm using an object factory; it has to go on the free-store.

What style of code would you recommend here?

-- James Dennett <jdennett@acm.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              ]






Author: niklasb@my-deja.com
Date: 1999/09/30
Raw View
In article <IO7I3.339$tk3.191@news.get2net.dk>,
  "Anders J. Munch" <andersjm@dancontrol.dk> wrote:
>
> niklasb@my-deja.com wrote in message <7so9tr$k8s$1@nnrp1.deja.com>...
> [...]
> >Insertion increases the number of elements, so how could a
> >"one-element container" support insertion?
>
> By having 0 or 1 elements.  If it will make you happier I can add some
> more.

But your container starts with one element. The statement you
describe as insertion does not add a new element, it changes
the value of the existing element.

> >> meaning_of_everything.first_and_only_element = 5;
> >>
> >> is not legal, because first_and_only_element is const.
> >
> >That's assignment not insertion.
>
> Performing insertion by means of assignment is perfectly
reasonable. ...

The fact that one may implement insertion using assignent does
not imply that insertion and assignment are the same thing.

Assignment changes the value of the existing object specified
by the left-hand expression to the value of the right-hand
expression.

Insertion creates a new object, initialized with a given
value, and adds that object to the container.

> ... It
> is not the object proper (as identified by a unique addresss) that is
> inserted, it is its value.  The only way to store the original object
> (type T) on its original address is to store some kind of pointer to
the
> object, but then that is what I would call a Container<T*>, not a
> Container<T>.

I never said anything about inserting pointers. Inserting a
value is still different than assigning one.

The following implementation is crude and incomplete, but it
does demonstrate that insertion at least can be implemented
for containers of const objects. (It compiles with no errors
and does not use any casts.)


template<class T>
class Container {
private:
    struct Node {
        Node(const T& val) : rep(val)
        {
            next = 0;
        }

        Node* next;
        T rep;
    };

public:
    Container()
    {
        first = 0;
    }

    ~Container()
    {
        Node* p = first;
        while (p != 0) {
            Node* q = p;
            delete p;
            p = q;
        }
    }

    class Iterator {
    public:
        Iterator(Node* p) : p(p)
        {
        }

        Iterator& operator++ ()
        {
            p = p->next;
            return *this;
        }

        T& operator*()
        {
            return p->rep;
        }

    private:
        Node* p;
    };

    Iterator push_front(const T& val)
    {
        Node* p = new Node(val);
        p->next = first;
        first = p;
        return Iterator(p);
    }

private:

    Node* first;
};

void Test()
{
    typedef Container<const int> Cont;

    Cont myCont;
    Cont::Iterator i = myCont.push_front(1);
    Cont::Iterator j = myCont.push_front(2);
}


Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/09/30
Raw View
In article <37F2D66F.DBCBD0CD@ihug.co.nz>, ross.s@ihug.co.nz says...

[ ... ]

> I'm pretty neutral on the delete-const question; I lean mildly towards
> the ARM rule but don't feel particularly strongly about it, so I think I
> can claim to be a reasonably neutral observer. As I understand Nathan's
> position, he has expressed no opinion on the question of "Should
> deletion through pointer to const be allowed?" (or if he has, he's
> clearly noted that it's irrelevant to his main argument).

Hmm...here's a quote from one of Nathan's posts early in this thread:

 The "choice between two features" was not the choice voted on
 in committee, and it is not a choice under discussion here.
 The choice voted on in committee was whether to break const
 semantics.

That certainly sounds to me like he considers the earlier rule correct
and the current one incorrect -- I.e. "broken"  He went on to say:

 The committee chose "yes" based on arguments presented which
 have been demonstrated to be specious.  Additional arguments
 have since been advanced, also demonstrated to be specious.

Now, as it's usually used, "demonstrated to be specious" would
indicate that everybody involved has agreed that the arguments were
specious.  For example, one might "demonstrate" the speciousness of an
argument that the world is flat.  That is NOT the situation here: he's
_argued_ (rather than demonstrated) that the points were illogical,
specious, etc., but apparently has not convinced his opponents of
this.  Thus, rather than "demonstrated", his statement should be that
each of these points was "argued unconvincingly" or something on that
order -- note that I'm not saying his arguments were wrong, only that
they didn't convince his opponents.

To continue after the quote above, Nathan did exactly the sort of
thing he recently objected to -- he posted what he considered his
opponents positions to be:

 Thus far we have seen
      (summarizing):
              analogy to auto objects (irrelevant to the question)
              analogy to Unix permissions (invalid analogy)
              template can't delete T (demonstrated otherwise)
              want containers of const T (still illegal)
              language lacks non-const no-delete feature (irrelevant)
           and now
              const wasn't useful anyway

In the interest of minimizing fire damage, I'll refrain from posting
my (off topic) opinion of somebody who summarizes his opponent's
position, then cries "foul" when somebody attempts to summarize his
position.  I will note for the record though, that he didn't simply
say that Francis's summary was wrong, but that even making an attempt
at posting it was (in his opinion) wrong...

[ ... ]

> Conflating a claim that "this specific argument in favour of X is wrong"
> with one that "X is wrong" is a fundamental error that I would have
> thought anyone sufficiently competent at elementary logic to make a
> living as a programmer would never make.

He only started talking about their arguments (and unwillingness to
accept his arguments) being illogical AFTER it became apparent that
the arguments he was making weren't convincing anybody.

My own position on the original subject is fairly simple: it's been
decided.  While we could sit back and argue whether the committee's
decision was the best one, there's not much to do about it now.  If
enough people became convinced that this was a colossal mistake, the
next round of standardization could change the rule back to the way it
was in the ARM.  This, however, would almost certainly break quite a
large amount of code, so a LOT of people will have to be convinced
that the change was truly a colossal blunder before a change is
likely.  I seriously doubt that'll happen, but if it does, I'm pretty
sure it WON'T be by Nathan Myers alienating as many committee members
as he can.

--
    Later,
    Jerry.

The universe is a figment of its own imagination.
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/28
Raw View
I would like to thank Andrei for his admirably clear exposition,
and take the opportunity to respond as requested, but also point
out a few errors.

Andrei Alexandrescu  <andrewalex@hotmail.com> wrote:
> Let me start by making an off-topic consideration. For participants to
> this newsgroup, thinking is fun. Solving problems is fun. Exposing
> arguments is fun. Generalizing and finding the concept behind a
> behavior is fun. That's what we *enjoy*, otherwise we wouldn't have
> been on such a newsgroup. Please don't forget this as you post in this
> thread.

I have certainly been enjoying it.  I hope everyone else has, as well.


> As far as I understand, "delete const" supporters' main argument is that
> if some entity created an object, that entity should be able to destroy
> it. If the language doesn't allow this, there is something wrong with it.

I think the statement must be "be able to destroy it without a cast".
No one has introduced a case of something that should be destroyed,
but cannot be.


> As far as I understand, "delete const" detractors' main argument is that
> enabling deletion of const objects just like that is a severe violation
> of everything const is all about. If the language allows this, there is
> something wrong with it. (Yes, I did copy/paste.)
>
> ...
> I guess there are the following questions that must be answered in
> order for us to understand the problem better:
>
> 1. Does the Standard leave an opportunity for a genuine constant free
> store?
>
> The Standard says that "new int" and "new const int" are different
> expressions. The const is not ignored, the second expression will
> return a const int*, and if you cannot apply delete to that pointer, it
> means that the language enabled you to create something that you simply
> cannot delete.  ... the "const free store" issue is tightly
> bound to the "delete const" issue.

In the interests of fairness (and I think Andrei must have missed this
when it came up before): in the ARM, "new int" and "new const int" _were_
identical.  Breaking this equivalence happened as part of the project
that broke const itself, so their new non-equivalence cannot be entered
on one side of the issue.


> 2. Why is the explicit destructor call allowed for const objects?
>
> As we all know, from our discussion's viewpont, this code fragment is
> perfectly legal:
>
> {
>    const Something obj;
>    ...
> }  // obj.~Something() automatically invoked
>
> This suggests that the destructor should be invokable for const
> objects. Following this line of thought, the committee has enabled
> explicit destructor calls for const objects:
>
> void f(Something& toBeNuked)
> {
>     // aw!
>     toBeNuked.~Something();  // legal
> }
>
> There were a couple of examples that justify this, however I forgot
> them. What I want to emphasize here is that the issue of "delete const"
> is tied to this issue, too.

The committee did not _enable_ explicit destructor calls on const objects.
It inherited them from Cfront, via the ARM.

The argument for retaining that laxity is that such a call necessarily
involves manipulating raw storage (afterward), and work with raw storage
cannot benefit much from type system restrictions, even before the fact.

This is a purely practical argument; pedantics would dictate enforcing
const here as well.


> 3. What special rights does creating an object (const or not) give to
> you?
>
> Consider these two functions:
>
> void f()
> {
>     const Something obj;
>     // use obj
> }
>
> void g(const Something& obj)
> {
>     // use obj
> }
>
> The question is: is there anything extra that f() can do with obj, that
> g() cannot? Both can call only const methods of it, both can access
> only public members of it (assuming they're not friends of Something),
> and so on.
>
> In addition, the compiler inserts a call to the destructor at the end
> of f(), and here's Pandora's purse. Oh, this means f() does something
> extra! But in light of (2), g() can destroy its obj just as well. Plus,
> it's not the user code, it's the compiler the one that inserts the call
> to the destructor, and we all C++ programmers know that the compiler
> can do things that we cannot. So it seems that as far as automatic
> objects go, there's no much extra rights that you have just because
> you're the one who created the object.
>
> I will leave upt to you to discuss what rights you should and should
> not have for objects created on the free store. Don't forget, though,
> that this is linked with the "const free store" issue (1).

As mentioned above, I don't think _anything_ can be linked, fairly, with
the "const free store issue".  The late invention of "const free store"
has been the cause of much violence to the core language, and that
violence is far from completed.


> 4. What does const guarantee, and what does it not?
>
> Here's another hot spot. I propose we scrap the discussion about casts
> altogether. Paraphrasing Dostoievski (I recall) who said: "If God
> doesn't exist, everything's possible", I'd say: "If a cast does exist,
> everything's possible".
>
> Let's face it, folks, with casts can do whatever you want on any design
> and most language rules, no matter how carefully they're taken care of.
> Let's discuss what const means if you *don't* use casts.
>
> It all boils down to the question: "If I pass a pointer to const to
> someone, is it reasonable for that someone to delete that pointer
> without using any black magic"?

And the related question, "If I have a pointer-to-const I created,
is it really black magic to cast away the const?"


> 5. How often do Andrew's situation and Nathan's situation appear in
> practice?
>
> C++ is a practical language, and practicality pervades its design.

Probably "suffuses" is a better choice of word.  :-)

> It would be in order, I think, if we answered the question: which
> situation would cause more harm and more good in practice? As Scott
> Meyers has put it, you folks *forgot* more C++ than most programmers
> will ever know, so it's important to know what's the mainstream usage
> of a feature.
>
> There are historical precedents to this. Some things that would have
> made sense conceptually have been disabled because of practicality
> issues.
>
> Andrew told me in private correspondence that in teaching C++, he often
> found himself with the now well-known example:
>
> template <class T> void f(T& t)
> {
>     T* p = new T;
>     ...
>     delete p;
> }
>
> Explaining that this is not possible if T is a const type would be
> really awkward, and it would basically raise the question if the
> language is right in forbidding this.
>
> To this example, a number of people responded with solutions (that
> would make the example compilable without taking advantage of delete
> const), that can be considered hacks. So there's a way out of it, but
> it's not easy to explain and to understand.

I wonder if (and how) Andrew now explains to these students why
they should never assign anything to a *p, just in case T happens
to be a const type; and what he suggests they should do instead.

It strikes me that this (supposed) difficulty has not been banished,
or much reduced, by the change; it has only shifted to those remaining
operations which const still affects.  If we eliminate _all_ enforcement
of const, the difficulty (such as it is) will finally disappear.  No
code would break, but would the result be good?


> Andrew links this small example with creating containers of const
> objects. Anyway, I'd be glad to see more fleshy examples of those
> template functions, not only "..." between new and delete.
>
> On the other hand, Nathan is in a different position in giving
> examples: it's not that the language wouldn't allow something, it's the
> opposite: outrageous things happen just by default, and the compiler
> allows them to happen without lifting a finger. Nathan can (and I
> invite him to) come with a body of examples and situations when
> innocent code, code that doesn't use any feature of C++ that hasn't
> been widely known for years, wreaks havoc. This is because the current
> rule allows bad things to happen, and Andrew acknowledged that.
>
> For what it's worth, here are a couple of personal considerations that
> don't lead anywhere, but they might provide a starting point. So, IMHO
> most C++ programmers:
> a) don't explicitly call destructors
> b) do know how to call delete and they're not coy with it
> c) don't delete the address of a reference; they delete pointers
> d) don't write template code on a regular basis
> e) if they write template code, they know a lot of stuff
> f) if they write template containers, they know even a bigger amount of
>    stuff

Agreed, on all counts.  I would say "they need to know" rather than
"they know".


> Of course, maybe some things will change in the next few years, and I
> actually hope so.
>
> So, I invite the participants to respond to the points above. Not that
> I think they really care about my posting. (C'mon, guys, after all this
> effort...)
>
> Again, I think the real debate is - what does more sense: breaking
> the "I created it, I must be able to destroy it" rule (and getting over
> it with a hack), or living at the risk of const objects being deleted?

That debate is necessarily moot; the decision has been made, for better
or worse.

I would be happy to see just a single logically-valid argument in
favor of the change that occurred.  (I'm assuming, brightly, that such
is possible.)  Failing that, I would be happy to see an acknowledgement
from someone who favored the change that _any_one_ of the arguments
presented repeatedly in support of the change was in fact logically
invalid.  (I might propose the "it's ok to delete it because it already
doesn't exist" one, if you don't know where to begin.)

Of course, admitting the presence of invalid arguments doesn't weaken any
valid arguments, assuming (as I have chosen, for sake of argument, to do)
that the latter exist.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/28
Raw View
In article <7sokmv$s6v$1@nnrp1.deja.com>, Andrei Alexandrescu
<andrewalex@hotmail.com> writes
>Again, I think the real debate is - what does more sense: breaking
>the "I created it, I must be able to destroy it" rule (and getting over
>it with a hack), or living at the risk of const objects being deleted?

Thanks.  But the problem is that Nathan keeps saying that the current
position is (in my terms) 'water under the bridge' and what interests
him is how such sane and intelligent people could change the 'manifestly
correct' ARM position to the 'broken' ISO/ANSI C++ position.





Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/09/28
Raw View
Andrei Alexandrescu wrote in message <7sokmv$s6v$1@nnrp1.deja.com>...
>Gentlemen!

[...]

I don't know if this responds to any specific one of your questions.
Nonetheless, here goes.

This entire conversation sent me poring over all the C++ code I've written
in the past several years. I'm not suggesting that it's representative, but
what I found was that I rarely if ever tried to do this:

const a* ap = new a(1,2,3);
// ...
delete ap;

If I ever did, I changed it because older compilers did not permit it. As I
recall, there were some times when I blamed it on the compiler, not knowing
about the ARM rule. A small oversight. Guys like me ought to know about such
things, but this one slipped by me. Nonetheless, there never seemed a time
when it was necessary to use const to protect my objects from myself. So the
argument that this usage justifies the change does not convince me. Mind, I
had to go back and read old code to realize that. The template problem seems
more persuasive, but I've never wanted to instantiate a container of const
objects, so I am not yet moved by that argument. So perhaps I am addressing
your question about how often have the various idioms of the issue opponents
found their way into our code.

Here, however, is where the bad part comes in:

void f(const a* ap);

a* ap = new a(1,2,3);
f(ap);
delete ap;

The guarantee once made by the prototype that f will not delete ap is gone.
That is a bad thing and is a flaw in the language. None of the arguments
presented here in this thread have convinced me otherwise. It took me a
while to get to that conclusion, and I was almost deflected by the tone of
some of the debate and efforts to make the conversation about the process of
disagreement rather than about the technical merits of the issues. Not that
such discussions are irrelevant when you include the topic of
standardization in your charter; but they do tend to obscure the more
interesting points, which have more to do with code and compilers and less
to do with coders and language specifiers.
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/28
Raw View
Lisa Lippincott  <lisa_lippincott@bigfix.com> wrote:
>Nathan Myers <ncm@nospam.cantrip.org> wrote:
>> ... nobody even mentioned "containers of const T" until the
>> question came up about what utility is supposed to have been
>> provided by breaking const.  If they were so useful, why hadn't
>> anyone written any before?  They were certainly possible (easy,
>> actually) before, as after, the breakage.
>
>For what it's worth, I have written, and routinely use, (non-STL)
>container templates which work for const parameters. ...

OK, that question is settled.

>While these containers didn't delete any const objects (and so had
>no problems with the ARM rule), they did explicitly destroy const
>objects.  I don't know where the opponents of delete-const stand on
>that issue.

Since you asked...
It would have improved consistency to have disallowed calling the
destructor on non-const object references.

The effect of such a change on your containers would be that the
"unconst()" template mentioned elsewhere, or something like it,
would have been needed.  The minimal approach would be to use
a variant of the traditional-STL "destruct" function:

  template <class T> void const_destruct(T const* p)
    { const_cast<T*>(t)->T::~T(); }

and code that read

   p->T::~T();

would need to be changed to

  const_destruct(p);

Stepanov appears to prefer the latter form anyhow, probably because
he favors very long template formal-argument names, and the former
repeats the name twice while the latter doesn't mention it at all.

There was no proposal to tighten up const-safety on explicit destructor
calls because, first, it would have broken code, and second, anyone
using explicit destructor calls is manipulating raw storage, where the
type system can be of no help.  (You can't accidentally make an explicit
destructor call.)

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/28
Raw View
niklasb@my-deja.com wrote in message <7so9tr$k8s$1@nnrp1.deja.com>...
[...]
>Insertion increases the number of elements, so how could a
>"one-element container" support insertion?

By having 0 or 1 elements.  If it will make you happier I can add some
more.

template <typename T>
struct SimpleTenElementContainer
{
    SimpleTenElementContainer() : size(0) {}
    T elements[10];
    size_t size;
};

>> meaning_of_everything.first_and_only_element = 5;
>>
>> is not legal, because first_and_only_element is const.
>
>That's assignment not insertion.

Performing insertion by means of assignment is perfectly reasonable.  It
is not the object proper (as identified by a unique addresss) that is
inserted, it is its value.  The only way to store the original object
(type T) on its original address is to store some kind of pointer to the
object, but then that is what I would call a Container<T*>, not a
Container<T>.

- Anders




[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/29
Raw View
Francis Glassborow  <francisG@robinton.demon.co.uk> wrote:
>... Nathan keeps saying that ... what interests him is how
>such sane and intelligent people could change the 'manifestly
>correct' ARM position to the 'broken' ISO/ANSI C++ position.

I would like it known that Francis Glassborow has repeatedly posted
false and misleading "summaries" of my writings.

Francis, I have asked you already not to put words in my mouth.
Your characterization of my "interest" is entirely opposed to what
I have explained here many, many times.  I have never mentioned,
used, or even hinted at, the concept 'manifestly correct'.  The
discussion was never about how the committee "could change" const;
This discussion is about the quality of argumnets posted here.

Was this a troll?

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: Lisa Lippincott <lisa_lippincott@bigfix.com>
Date: 1999/09/29
Raw View
Nathan Myers <ncm@nospam.cantrip.org> wrote:
> In the interests of fairness (and I think Andrei must have missed this
> when it came up before): in the ARM, "new int" and "new const int" _were_
> identical.

While it can be difficult to argue fine the points of ARM C++, I think
the statement above is flatly false.

In a picayune sense, it is false because "new const int" is not
allowed at all by the ARM:

      The type-specifier-list [of an allocation-expression] may
      not contain const, volatile, class declarations, or
      enumeration declarations.                 5.3.3 [New]

But we know that such an expression isn't the only way for a dynamic
object to be const-qualified.  In particular, classes containing
const members may be allocated dynamically.  In that case, I see
no reason that the basic definition of const would not apply:

      A const object may be initialized, but its value may not
      be changed thereafter.                    7.1.6 [Type Specifiers]

Section 7.1.6 goes on to discuss the practical difficulties of an
implementation preventing such changes, but I don't see anything which
suggests that this program

      struct S
        {
         const int n;
         S( int i ) :n(i) {}
        };

      int main()
        {
         S *p = new S(0);
         ((S*)(p))->n = 5;
        }

must not cause an addressing exception.

                                                   --Lisa Lippincott


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/27
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>Anders J. Munch <andersjm@dancontrol.dk> wrote:
>
>>I don't know what he meant, and so I asked him to elaborate.
>
>I meant Container<const T>.

I'm happy to stipulate that Container<const T> could conceivably
be useful.  It might have a member, top(), which returns a T&.
Users might want to add things to it, and rearrange their order,
but be protected against clobbering the values without a cast.
(With a cast they can clobber them anyhow.)

Of course, if they happened to instantiate Container<U const* const>,
they could clobber those elements (by deleting) without a cast,
but this is _said_ to be OK.

To write the code to implement Container<>, however, you must be very
careful about depending on any non-const operations on T.  (None of the
STL containers are so written, to my knowledge.)  In a typical such
container, in fact, occasional casts will be needed anyway.  Being
able to delete without a cast adds no essential capability, or even
convenience, in this case.

Thus far the Container<const T> example is the only one that has surfaced
attempting to illustrate actual utility in having broken const, and it
does not withstand scrutiny.   Container<const T> was always possible,
as has been illustrated elsewhere, but now it is demonstrably less safe.

That this example keeps popping up despite the problems noted above
fascinates me.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/27
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>Dave Harris <brangdon@cix.co.uk> wrote:
>
>>It wasn't necessary to change the ARM rule to get container<const T>.
>
>Perhaps not necessary, but certainly useful.

That has not even begun to be demonstrated.

First, nobody even mentioned "containers of const T" until the
question came up about what utility is supposed to have been
provided by breaking const.  If they were so useful, why hadn't
anyone written any before?  They were certainly possible (easy,
actually) before, as after, the breakage.

Second, since it was so easy to write containers of const T even
before having broken const, it cannot be said that it was useful
to have broken it, just for containers.  If, indeed, it was useful
to have broken const, no one has yet proposed anything that it
was (after examination) actually useful for.

Of course it is very odd to have made a sweeping language change
without demonstrating utility _first_, but better late than never,
I suppose.

--
Still waiting,
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/09/27
Raw View
Nathan Myers wrote:
....
> First, nobody even mentioned "containers of const T" until the
> question came up about what utility is supposed to have been
> provided by breaking const.  If they were so useful, why hadn't
> anyone written any before?  They were certainly possible (easy,
> actually) before, as after, the breakage.

Just because they hadn't been mentioned, they hadn't been written? I
haven't mentioned before in this newsgroup that I have a brother - does
that mean he must be a newborn?


[ 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: niklasb@my-deja.com
Date: 1999/09/27
Raw View
In article <Ly2H3.150$yu2.236@news.get2net.dk>,
  "Anders J. Munch" <andersjm@dancontrol.dk> wrote:
>
> James Kuyper Jr. wrote in message <37EA2299.1BAFE86C@wizard.net>...
> [...]
> >> A container into which nothing can be inserted??  Would you specify
> >> entire contents in the construction phase?  Please elaborate.
> >
> >They can't be changed; that says nothing about whether or not they
can
> >be inserted. Are you confusing 'Container<const T>' with 'const
> >Container<T>'?
>
> I knew what I meant, but perhaps I should have written it down :-)
I'll
> try a example, for simplicity it's just a one-element container.

Insertion increases the number of elements, so how could a
"one-element container" support insertion?

>...
> meaning_of_everything.first_and_only_element = 5;
>
> is not legal, because first_and_only_element is const.

That's assignment not insertion.



Sent via Deja.com http://www.deja.com/
Before you buy.


[ 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: Lisa Lippincott <lisa_lippincott@bigfix.com>
Date: 1999/09/27
Raw View
Nathan Myers <ncm@nospam.cantrip.org> wrote:
> First, nobody even mentioned "containers of const T" until the
> question came up about what utility is supposed to have been
> provided by breaking const.  If they were so useful, why hadn't
> anyone written any before?  They were certainly possible (easy,
> actually) before, as after, the breakage.

For what it's worth, I have written, and routinely use, (non-STL)
container templates which work for const parameters.  While I haven't
studied the problem closely, I think the approach I used would
work for STL containers, modulo the unfortunate definition of
map<T>::operator[].

While these containers didn't delete and const objects (and so had
no problems with the ARM rule), they did explicitly destroy const
objects.  I don't know where the opponents of delete-const stand on
that issue.

The containers I wrote did, however, have problems with the lack
of C++ facilities for dealing with uninitialized storage; I posted
a fairly ambitious suggestion along those lines in
<http://www.deja.com/getdoc.xp?AN=512556930&fmt=text>

                                                --Lisa Lippincott


[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/27
Raw View
On 27 Sep 1999 18:38:50 GMT, Lisa Lippincott <lisa_lippincott@bigfix.com> wrote:

>For what it's worth, I have written, and routinely use, (non-STL)
>container templates which work for const parameters.  While I haven't
>studied the problem closely, I think the approach I used would
>work for STL containers, modulo the unfortunate definition of
>map<T>::operator[].

To make a std::container<const T> work, have you considered writing
a const_allocator<> class rather than a whole new container class?
I'm not 100 per cent sure, but I think it will work.

--
--------------
siemel b naran
--------------


[ 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: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/09/27
Raw View
Gentlemen!


This thread is so long, I didn't know where to hook my response in, so
I chose a random recent message. This article is not a specific reply
to it. It tries to be an overview of what happened so far, and an
attempt to provide a collection of questions that would keep us focused.

Let me start by making an off-topic consideration. For participants to
this newsgroup, thinking is fun. Solving problems is fun. Exposing
arguments is fun. Generalizing and finding the concept behind a
behavior is fun. That's what we *enjoy*, otherwise we wouldn't have
been on such a newsgroup. Please don't forget this as you post in this
thread.

As far as I understand, "delete const" supporters' main argument is that
if some entity created an object, that entity should be able to destroy
it. If the
language doesn't allow this, there is something wrong with it.

As far as I understand, "delete const" detractors' main argument is that
enabling deletion of const objects just like that is a severe violation
of everything const is all about. If the language allows this, there is
something wrong with it. (Yes, I did copy/paste.)

There are a lot of other additional arguments that were brought in, but
mainly they either are consequences of the above, or they are not as
essential. I think that if one of the two arguments above falls apart,
the people sustaining it will be convinced to think otherwise. Of
course, I don't have any realistic hope of this happening.

I guess there are the following questions that must be answered in
order for us to understand the problem better:


1. Does the Standard leave an opportunity for a genuine constant free
store?

The Standard says that "new int" and "new const int" are different
expressions. The const is not ignored, the second expression will
return a const int*, and if you cannot apply delete to that pointer, it
means that the language enabled you to create something that you simply
cannot delete.

In another thread, Lisa Lippincot has noticed a defect in the standard.
Please read her article "Defect Report Reanimation of dynamic const
objects". If the Committee decides that's not a defect, that
effectively wipes any opportunity for any genuine const free store.

No matter what the outcome is, the "const free store" issue is tightly
bound to the "delete const" issue.


2. Why is the explicit destructor call allowed for const objects?

As we all know, from our discussion's viewpont, this code fragment is
perfectly legal:

{
   const Something obj;
   ...
}  // obj.~Something() automatically invoked

This suggests that the destructor should be invokable for const
objects. Following this line of thought, the committee has enabled
explicit destructor calls for const objects:

void f(Something& toBeNuked)
{
    // aw!
    toBeNuked.~Something();  // legal
}

There were a couple of examples that justify this, however I forgot
them. What I want to emphasize here is that the issue of "delete const"
is tied to this issue, too.


3. What special rights does creating an object (const or not) give to
you?

Consider these two functions:

void f()
{
    const Something obj;
    // use obj
}

void g(const Something& obj)
{
    // use obj
}

The question is: is there anything extra that f() can do with obj, that
g() cannot? Both can call only const methods of it, both can access
only public members of it (assuming they're not friends of Something),
and so on.

In addition, the compiler inserts a call to the destructor at the end
of f(), and here's Pandora's purse. Oh, this means f() does something
extra! But in light of (2), g() can destroy its obj just as well. Plus,
it's not the user code, it's the compiler the one that inserts the call
to the destructor, and we all C++ programmers know that the compiler
can do things that we cannot. So it seems that as far as automatic
objects go, there's no much extra rights that you have just because
you're the one who created the object.

I will leave upt to you to discuss what rights you should and should
not have for objects created on the free store. Don't forget, though,
that this is linked with the "const free store" issue (1).


4. What does const guarantee, and what does it not?

Here's another hot spot. I propose we scrap the discussion about casts
altogether. Paraphrasing Dostoievski (I recall) who said: "If God
doesn't exist, everything's possible", I'd say: "If a cast does exist,
everything's possible".

Let's face it, folks, with casts can do whatever you want on any design
and most language rules, no matter how carefully they're taken care of.
Let's discuss what const means if you *don't* use casts.

It all boils down to the question: "If I pass a pointer to const to
someone, is it reasonable for that someone to delete that pointer
without using any black magic"?


5. How often do Andrew's situation and Nathan's situation appear in
practice?

C++ is a practical language, and practicality pervades its design. It
would be in order, I think, if we answered the question: which
situation would cause more harm and more good in practice? As Scott
Meyers has put it, you folks *forgot* more C++ than most programmers
will ever know, so it's important to know what's the mainstream usage
of a feature.

There are historical precedents to this. Some things that would have
made sense conceptually have been disabled because of practicality
issues.

Andrew told me in private correspondence that in teaching C++, he often
found himself with the now well-known example:

template <class T> void f(T& t)
{
    T* p = new T;
    ...
    delete p;
}

Explaining that this is not possible if T is a const type would be
really awkward, and it would basically raise the question if the
language is right in forbidding this.

To this example, a number of people responded with solutions (that
would make the example compilable without taking advantage of delete
const), that can be considered hacks. So there's a way out of it, but
it's not easy to explain and to understand.

Andrew links this small example with creating containers of const
objects. Anyway, I'd be glad to see more fleshy examples of those
template functions, not only "..." between new and delete.

On the other hand, Nathan is in a different position in giving
examples: it's not that the language wouldn't allow something, it's the
opposite: outrageus things happen just by default, and the compiler
allows them to happen without lifting a finger. Nathan can (and I
invite him to) come with a body of examples and situations when
innocent code, code that doesn't use any feature of C++ that hasn't
been widely known for years, wreaks havoc. This is because the current
rule allows bad things to happen, and Andrew acknowledged that.

For what it's worth, here are a couple of personal considerations that
don't lead anywhere, but they might provide a starting point. So, IMHO
most C++ programmers:
a) don't explicitly call destructors
b) know how to call delete and they're not coy with it
c) don't delete the address of a reference; they delete pointers
d) don't write template code on a regular basis
e) if they write template code, they know a lot of stuff
f) if they write template containers, they know even a bigger amount of
stuff

Of course, maybe some things will change in the next few years, and I
actually hope so.

So, I invite the participants to respond to the points above. Not that
I think they really care about my posting. (C'mon, guys, after all this
effort...)

Again, I think the real debate is - what does more sense: breaking
the "I created it, I must be able to destroy it" rule (and getting over
it with a hack), or living at the risk of const objects being deleted?

Sorry for this long posting.


Cheers,

Andrei


Sent via Deja.com http://www.deja.com/
Before you buy.


[ 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: Lisa Lippincott <lisa_lippincott@bigfix.com>
Date: 1999/09/28
Raw View
Andrei Alexandrescu <andrewalex@hotmail.com> wrote:
> Gentlemen!
[Hah!]
> In another thread, Lisa Lippincot has noticed a defect in the standard.
> Please read her article "Defect Report Reanimation of dynamic const
> objects". If the Committee decides that's not a defect, that
> effectively wipes any opportunity for any genuine const free store.

I wouldn't go that far -- even const objects on the heap are subject
to 7.1.5.1 [dcl.type.cv], paragraph 4:

    Except that any class member declared mutable (7.1.1) can be modified,
    any attempt to modify a const object during its lifetime (3.8) results
    in undefined behavior.

To me, that paragraph expresses the core meaning of const.  The proposed
defect is that, in some situations, compilers can't take advantage of
this property to perform optimizations.

                                                --Lisa Lippincott


[ 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: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/25
Raw View
James Kuyper Jr. wrote in message <37EA2299.1BAFE86C@wizard.net>...
[...]
>> A container into which nothing can be inserted??  Would you specify
>> entire contents in the construction phase?  Please elaborate.
>
>They can't be changed; that says nothing about whether or not they can
>be inserted. Are you confusing 'Container<const T>' with 'const
>Container<T>'?

I knew what I meant, but perhaps I should have written it down :-)  I'll
try a example, for simplicity it's just a one-element container.

template<typename T>
struct SimpleOneElementContainer
{
    SimpleOneElementContainer(T t)
    : first_and_only_element(t) {}

    T first_and_only_element;
};

For T == const int, this will expand into:

struct SimpleOneElementContainer<const int>
{
    SimpleOneElementContainer(const int t)
    : first_and_only_element(t) {}

    const int first_and_only_element;
};

Now try:

SimpleOneElementContainer<const int> meaning_of_everything = 42;

This works, because the const member is initialized in the constructor.
But..

meaning_of_everything.first_and_only_element = 5;

is not legal, because first_and_only_element is const.

Conclusion: A Container<const T> cannot be inserted into except during
the construction phase.  Having such a container doesn't seem to be of
much use.

Andrew Koenig has a valid wish for a container that can store values
that should not change while in the container, but a Container<const T>
will never be such a beast.  He could try a Container<const T*>, of
course, and maybe this is what he meant.  I don't know what he meant,
and so I asked him to elaborate.

- Anders




[ 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: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/25
Raw View
blargg wrote in message ...
[...]
>    Container<T const> // this is what was being discussed

[...]
>    container.push_back( 1234 ); // OK

No, this is impossible, at least without a cast.  See my reply to James
Kuyper Jr.

- Anders




[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/09/25
Raw View
In article <Ly2H3.150$yu2.236@news.get2net.dk>,
Anders J. Munch <andersjm@dancontrol.dk> wrote:

>Andrew Koenig has a valid wish for a container that can store values
>that should not change while in the container, but a Container<const T>
>will never be such a beast.  He could try a Container<const T*>, of
>course, and maybe this is what he meant.  I don't know what he meant,
>and so I asked him to elaborate.

I meant Container<const T>.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/09/24
Raw View
"Anders J. Munch" wrote:
>
> Andrew Koenig wrote in message ...
> >
> >In article <37DD73C6.62A4752F@ihug.co.nz>,
> >Ross Smith  <ross.s@ihug.co.nz> wrote:
> >
> >>> The question is how much work the author of this class has to do
> >>> in order to enable a Container<const T> to work properly.
> >
> >>Why would you expect a Container<const T> to work properly? I
> wouldn't.
> >
> >Because that is how I would ask a container to store values
> >that should not change while in the container, which is something
> >that I have certainly wanted to do in practice.
>
> A container into which nothing can be inserted??  Would you specify
> entire contents in the construction phase?  Please elaborate.

They can't be changed; that says nothing about whether or not they can
be inserted. Are you confusing 'Container<const T>' with 'const
Container<T>'?

This was brought up specifically as an answer to a question about how it
could possibly be useful to dynamically create and destroy const
objects. Therefore, he's allowed to assume that it is possible
(particularly since the standard says that it is).
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/24
Raw View
In article <XY7G3.272$tz1.601@news.get2net.dk>, "Anders J. Munch"
<andersjm@dancontrol.dk> wrote:
> Andrew Koenig wrote in message ...
> >In article <37DD73C6.62A4752F@ihug.co.nz>,
> >Ross Smith  <ross.s@ihug.co.nz> wrote:
> >
> >>> The question is how much work the author of this class has to do
> >>> in order to enable a Container<const T> to work properly.
> >>
> >> Why would you expect a Container<const T> to work properly? I
> >> wouldn't.
> >
> > Because that is how I would ask a container to store values
> > that should not change while in the container, which is something
> > that I have certainly wanted to do in practice.
>
> A container into which nothing can be inserted??  Would you specify
> entire contents in the construction phase?  Please elaborate.

You misunderstand. Apply const to the contained type, not to the container
object.

    const Container<T> // no

    Container<T const> // this is what was being discussed

Understand?

    container.push_back( 1234 ); // OK

    *container.begin() = 1234; // no

    int i = *container.begin(); // OK
---
[ 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: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/23
Raw View
Andrew Koenig wrote in message ...
>
>In article <37DD73C6.62A4752F@ihug.co.nz>,
>Ross Smith  <ross.s@ihug.co.nz> wrote:
>
>>> The question is how much work the author of this class has to do
>>> in order to enable a Container<const T> to work properly.
>
>>Why would you expect a Container<const T> to work properly? I
wouldn't.
>
>Because that is how I would ask a container to store values
>that should not change while in the container, which is something
>that I have certainly wanted to do in practice.

A container into which nothing can be inserted??  Would you specify
entire contents in the construction phase?  Please elaborate.

- Anders
---
[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/23
Raw View
On 22 Sep 1999 18:08:20 GMT, Anders J. Munch <andersjm@dancontrol.dk> wrote:

>We are arguing whether it is or isn't logically consistent to disallow
>deletion of const objects.  Arguing over C++ tradition is besides the

Oh, I thought we were arguing about the design consequences.  I think
both points of view are logical in their own way.  To allow deleting
a pointer to const seems more logical though.  The rule that you can't
delete a pointer to const also has some logic, but it's greatest
virtue is that it makes C++ a little safer to use, and therefore it is
a good thing.

--
--------------
siemel b naran
--------------
---
[ 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: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/22
Raw View
Ziv Caspi wrote in message <37e732c0.394471970@news.netvision.net.il>...
[...]
>It all boils down to how we regard auto vars going out of scope.
>As far as I can tell, C++ has always treated this as if the programmer
>explicitly called destructors whenever appropriate (when scope
>ended, when exceptions are thrown, etc.).

We are arguing whether it is or isn't logically consistent to disallow
deletion of const objects.  Arguing over C++ tradition is besides the
point, unless you can show that the traditional view is the only
consistent one.  I have presented (in earlier posts) a different view
which IMHO is sound, and as such showing that the matter of auto object
destruction is no logical argument against disallowing delete-const.

I don't need to demonstrate that my view is _better_.  I just need to
demonstrate that it is _sound_, and then we can go on to discuss
practical engineering consequences.

> Its seems like you're
>arguing that *for const objects only*, removal of the "const"
>attribute is magically done by the compiler.

Please read my earlier posts under the subject line "Re: What const
is/was for (was: Re: delete of const objects o.k.?)".  No magic
involved.

[...] we must
>separate the "pure" (some say "theoretical", often in mocking)
>considerations of whether this change is technically better or not
>from the "practical" considerations of whether its utility is greater
>than its cost.

I'll add that seeking purity often leads to better practical designs.  I
just happen to believe that disallowing delete-const is the purer
decision.

- Anders




[ 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: zivca@netvision.net.il (Ziv Caspi)
Date: 1999/09/21
Raw View
[...Major snips ahead...]

On 19 Sep 1999 15:33:43 GMT, ncm@nospam.cantrip.org (Nathan Myers)
wrote:

>Andrew Koenig <ark@research.att.com> wrote:
>>One reason I believe that the analogy is valid -- and therefore that
>>creation/deletion is independent of modification -- is the behavior of
>>local variables.  There is absolutely no question that it is legal to
>>deallocate a local variable, even if it is const:
>>
>> { const int* p; { const int x = 3; p = &x; } }
>>
>>In this example, we have created a const object, placed its address in
>>a pointer, and then deallocated the object, leaving the pointer
>>invalid -- even though it is a pointer to const.
>
>"We" have *not* deallocated the object.

Actually, we did, simply by terminating its scope. We already have
an example for the "spirit" of C++ in this regard: Had x been of a
class type with private destructor, this code would have been
invalid.

It all boils down to how we regard auto vars going out of scope.
As far as I can tell, C++ has always treated this as if the programmer
explicitly called destructors whenever appropriate (when scope
ended, when exceptions are thrown, etc.). Its seems like you're
arguing that *for const objects only*, removal of the "const"
attribute is magically done by the compiler.

>>So then why is there even a question?  The most common argument I have
>>heard is that it is useful to be able to guarantee, for example, that
>>a function will not deallocate the object to which one of its
>>arguments points.  So, for example,
>>
>> extern void f(const T*);
>>
>>It would be nice to be able to look at that definition and see that
>>not only will f not modify the object to which its argument points,
>>but it won't delete that object either.
>
>Not only "would" it be nice; the guarantee *was* actively useful.
>Many thousands of interfaces were designed based on that guarantee.
>Those designs were then broken when their invariants could no longer
>be enforced.

This is an altogether different issue. This is not the first place
compatibility with previous drafts affected existing programs (like
operator new() starting to throw, for instance). However, we must
separate the "pure" (some say "theoretical", often in mocking)
considerations of whether this change is technically better or not
from the "practical" considerations of whether its utility is greater
than its cost.

---------------------------------------------
Ziv Caspi
zivca@netvision.net.il
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/19
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>
>The fundamental fact on which my thinking rests is that there is a
>distinction between an object and the contents of the object, and that
>it is possible to define operations on either one independently of
>the other.

C++ doesn't make this distinction.  Some objects have members, but
member access is not at issue here.

> In particular, allocation and deallocation are something
>you do to an object, and modification is something you do to the
>value of the object.

Allocation and deallocation occur outside the lifetime of the object,
so do not involve the object proper at all.  In the case of member
and auto objects, there is no issue: the language determines when the
lifetime ends.  Hence, attempts at analogies to members or autos can
only reveal, or produce, a deep confusion.

At issue is who should be allowed to end the lifetime of the object
when the language doesn't determine it.  No one can scrupulously reason
this out without considering engineering consequences.

>The Unix file system is a fine example of a design that makes this
>distinction explicit.

This false analogy was suggested in committee, and apparently influenced
votes.  It has been addressed before in this forum.  To address it
(<sigh>) again:

Unlinking files in Unix is _precisely_ equivalent to assigning zero to
a pointer in a garbage-collected run-time environment.  That is, the
Unix file system supports garbage collection; it has _no_ analog of
"delete".  Because no one has argued that

  void f(T const* tp) { tp = 0; }

should be, or should have been, forbidden, the analogy is at best
misleading.

To claim that an analogy to the Unix file system supported breaking
const is to argue that ordinary users should be allowed to "really
delete" Unix files regardless of the number of references to them.
This facility has been frequently requested for Unix, and has been
as frequently rejected, for sound reasons.

That the Unix file system analogy has surfaced again, here, after it
was so soundly demolished before, is worrisome.

>One reason I believe that the analogy is valid -- and therefore that
>creation/deletion is independent of modification -- is the behavior of
>local variables.  There is absolutely no question that it is legal to
>deallocate a local variable, even if it is const:
>
> { const int* p; { const int x = 3; p = &x; } }
>
>In this example, we have created a const object, placed its address in
>a pointer, and then deallocated the object, leaving the pointer
>invalid -- even though it is a pointer to const.

"We" have *not* deallocated the object.  Its lifetime ended independently
of anything we did.  This false analogy apparently also influenced votes.

As presented in committee, the analogy claimed was that the following

  { T const t; }  // implicit t.T::~T() invoked by compiler
  { T const* tp = new T; delete tp; }

should be equivalently legal.  This certainly looks reasonable, but the
example is deeply misleading.  The analogy stated in words is less
so: "Because the compiler handles destruction of auto objects which go
out of scope, _any_ code _anywhere_ (e.g. code in the same block where
it was created) should be able to delete _any_ dynamically allocated
object, regardless of constness."

The verbal description makes clear that the code example as constructed
distracts us from the real consequences of the change.

>As another example, there is no question that it is legal to delete a
>dynamically allocated object that contains a const member:
>
> struct X { X();  const int a; };
> int main() { X* xp = new X; delete xp; }
>
>Here, "delete xp;" deallocates a const object, namely member `a' of
>the object that was allocated by `new X'.  Again, there is no question
>that this is legal, because if it were not, there is no cast that
>could render it so.

"delete xp;" does _not_, in fact, deallocate a const object.  It
destroys a non-const X object.  After the (compiler-generated) X
destructor ends, the member `a' no longer exists, just as a local
variable no longer exists once it goes out of scope.  At issue is
whether the delete-expression (and, thus, to enter X's destructor)
should be legal under various circumstances; anything that happens
after the destructor is entered can have no bearing on the issue.

The sloppy thinking that led to Andrew's example above is just what
I meant to call to the attention of readers in this forum.

>So then why is there even a question?  The most common argument I have
>heard is that it is useful to be able to guarantee, for example, that
>a function will not deallocate the object to which one of its
>arguments points.  So, for example,
>
> extern void f(const T*);
>
>It would be nice to be able to look at that definition and see that
>not only will f not modify the object to which its argument points,
>but it won't delete that object either.

Not only "would" it be nice; the guarantee *was* actively useful.
Many thousands of interfaces were designed based on that guarantee.
Those designs were then broken when their invariants could no longer
be enforced.

The minutes don't suggest that breakage of existing designs had any
influence on the decision.

>Moreover, I agree with that argument!  It *would* be nice!  So why do
>I continue to think that the committee did the right thing to make
>this guarantee impossible to offer?
>
>The reason is that I think that if such a guarantee is tied to `const',
>it isn't strong enough to be useful.  In particular, as long as there
>is no way to define a function that *can* modify the object it is
>given, but *cannot* delete it, I consider such a guarantee to be of
>limited practical value.
>
>In other words, I want to be able to call a function such as
>
> X x;
> read(cin, &x);
>
>and be able to declare `read' in such a way as to be confident that it
>will not delete x, even though it can modify it.

In other words, because the language lacks a feature Andrew would like,
he defends breaking another, unrelated feature, despite that such
breakage got the language no closer to having the feature he would like.

>I continue to think that this is an issue about which reasonable
>people can disagree.

Each of the arguments Andrew raises above has been demolished before,
in this forum.  Andrew never defended the demolished arguments, yet he
has dragged them out again.

Evidently even very intelligent people can disagree unreasonably.
I find that very interesting, and it's why I raised this topic again.
Something about this subject brings out the worst in some very smart
individuals' reasoning powers.

If it has any lessons for us, it may be that we must insist on an
engineering analysis of the consequences of language changes, and
refuse to rely on woolly analogies.  Even very bright people are
easily led astray by appealing abstract arguments.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1999/09/20
Raw View
In article <37DD73C6.62A4752F@ihug.co.nz>,
Ross Smith  <ross.s@ihug.co.nz> wrote:

>> The question is how much work the author of this class has to do
>> in order to enable a Container<const T> to work properly.

>Why would you expect a Container<const T> to work properly? I wouldn't.

Because that is how I would ask a container to store values
that should not change while in the container, which is something
that I have certainly wanted to do in practice.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: zivca@netvision.net.il (Ziv Caspi)
Date: 1999/09/15
Raw View
On 14 Sep 99 10:35:09 GMT, ncm@nospam.cantrip.org (Nathan Myers)
wrote:

>Ziv Caspi <zivca@netvision.net.il> wrote:
>>
>>But you don't have to. You can just as easily bind const& to
>>a non-const auto variable.
>
>It is in fact _not_ "just as easy" to bind a const& to a
>non-const auto variable.
>
>Suppose you have functions declared as follows:
>
>  void f(T&);
>  void f(T const&);
>
>and you want to call the second one.

If I understand your point (here and elsewhere in this thread),
you seem to be arguing that there's no such thing as a const
object -- only const references/pointers.

Then you wouldn't mind this blanks fill-ins:

  T t;
  f( (T const&)t );

---------------------------------------------
Ziv Caspi
zivca@netvision.net.il
---
[ 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: James.Kanze@dresdner-bank.com
Date: 1999/09/15
Raw View
In article <slrn7trsa1.uk7.sbnaran@localhost.localdomain>,
  sbnaran@uiuc.edu wrote:

> On 13 Sep 1999 16:17:06 GMT, Andrew Koenig <ark@research.att.com> wrote:

> >The question is how much work the author of this class has to do
> >in order to enable a Container<const T> to work properly.

> Even within the current rules, a std::container<const T> is improper.
>
> Consider
>    std::container<const int> v(3,0);
> which creates a container of 3 elements, each initialized to '0'.

> I.
>
> To find space for 3 elements, the container calls the default
> allocator's allocate function.  In template form, it is
>
>    T * allocator<T>::allocate(size_type N) {
>       return static_cast<T *>(std::malloc(N*sizeof(T)));
>    }
>
> For T=="int const", it is
>
>    int const * allocator<int const>::allocate(size_type N) {
>       return static_cast<int const *>(std::malloc(N*sizeof(int const)));
>    }
>
> As static_cast cannot be used to add or remove const qualifiers, the
> cast is illegal.

What makes you say that? According to 5.2.9/6: "The inverse of any
standard conversion sequence, other than the lvalue-to-rvalue,
array-to-pointer, function-to-pointer, and boolean conversions, can be
performed explicitly using static_cast subject to the restriction that
the explicit conversion does not cast away constness."  Since int const*
to void* is a standard conversion, and void* to int const* doesn't cast
away const, it would seem legal.  (As an aside, I wonder whether the
standard isn't missing something about casting away volatile, as well.
int* to volatile void* is legal, but I hope that static_cast< int* >(
volatile void* ) isn't.)

> II.

> To construct each element, the container calls the default allocator's
> construct function.  In template form, it is
>
>    void allocator<T>::construct(T * place, const T& obj)
>    {
>       new (place) T(obj);
>    }
>
> For T=="int const", it is
>
>    void allocator<int const>::construct(int const * place, const const int& obj)
>    {
>       new (place) (const int)(obj);
>    }

> The call to placement new is illegal as it tries to modify a read-only
> location.

No.  There is no such thing as a read-only location for a constructor --
if an implementation does arrange to turn on write protection for
individual objects, it must arrange for it to be turned off during
constructors and destructors.  (At present, I know of no implementation
which will put an object with user-defined constructors or destructors
in write protected memory.)

However, placement new takes a void*, and there is no implicit
conversion from T const* to void*, only to void const*.  So this
effectively fails.

> The compiler must ignore two consts in a row in implicit template
> instantiation, so the declaration is legal.  Incidentally, this means
> that the following two functions are the same
>
>    typename allocator<T>::      pointer allocator<T>::address(reference);
>    typename allocator<T>::const_pointer allocator<T>::address(const_reference);

And if a fonction is defined twice, it is an error -- excellent point.

> Thus the rule that the compiler must ignore two consts in a row could
> be an error in the standard.  If it is an error, then the declaration
> is illegal too.

> (BTW, there was an issue that in expressions like
> std::bind2nd(std::mem_fun(&X::show),std::cout) we end up with a
> reference to a reference.  For example, because the function show
> is X::show(std::ostream&), the constructor of std::binder2nd is
>    std::binder2nd::binder2nd(const Oper&, const std::ostream& &);
> Forcing a reference to a reference to be a reference may cause
> problems as above.)

I seem to remember a special exception for this case -- a reference to a
reference resolves to a reference to the referred to object.

> III.

> To destroy the 3 elements, the container calls the default
> allocator's destroy function.  In template form, it is

>    void allocator<T>::destroy(T * obj) { obj->~T(); }

> For T=="int const", it is

>    void allocator<int const>::destroy(int const * obj) { obj->~T(); }

> It seems to me that this should be illegal, but by the current rules
> of C++, it is legal.

> IV.
>
> To deallocate the 3 elements, the container calls the default
> allocator's deallocate function.  In template form, it is

>    void allocator<T>::deallocate(T * array) { std::free(array); }

> For T=="int const", it is

>    void allocator<int const>::deallocate(int const * array) {std::free(array);}

> This is an error because the single argument of std::free is a "void *".

As far as I can tell, this implementation is non-conforming; the
standard requires calling ::operator delete.  But since the argument
type is still void*, and int const* does *not* convert implicitly to
void*, the problem remains unchanged.

Anyway, I think you've effectively proven that templates using separate
allocation and construction cannot be instantiated on a const type
unless they contain explicit const_cast's.

--
James Kanze                   mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ 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: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/16
Raw View
Andrew Koenig wrote in message ...
[...]
>The argument that I consider the strongest, and to which I have
>never seen a counterargument that is the least bit convincing,
>is that if you are allowed to create an object, you should be
>allowed to destroy it.

You have never seen a good counterargument against this?  Strange, because
IMHO your argument misses the point entirely.

I'd like to see you try invoking construction on an object .. something like
this?<g>

void f(SomeClass const * ob)
{ ob->SomeClass(); }

This is meaningless, of course, because object creation is something you
invoke on the *class*.  Object destruction, on the other hand, is something
you invoke on the *instance*.  Thus access to construct an object depends on
your access to the class; access to delete an object depends on your access
to the object instance in question.

Since 'const' controls the access to an *instance*, there is no reason why
it couldn't restrict the instance-oriented delete operation.

Then there is the example:

>That is, in
>
>template<class T> void f(args) {
>
>// ...
>
>}
>
>I should be able to say
>
>T* tp = new T;
>delete tp;

There is only a problem if T is a const type.  Let's call the non-const type
U:
    class U;
    typedef T const U;
Why would you want to create a const object?!   What is happening here is
that you are creating an object of class U, a 'U*' and assigning it to a 'U
const*' variable.  In doing that you have accidentally thrown away
accesibility.  I think you would be much happier simply creating a U object
and assigning it to a U* variable.  No accessibility lost, and even if
delete const is outlawed you would have no problem.

It seems that for the purpose of writing templates, C++ is lacking a means
of getting the non-const type from a const type.  But that is a different
issue, and allowing const delete doesn't "fix" it in general.  For an
example of another issue with constness problems in templates, see the
recent "typeof" discussion.

- Anders
---
[ 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: "Anders J. Munch" <andersjm@dancontrol.dk>
Date: 1999/09/16
Raw View
Andrew Koenig wrote in message ...
[...]
>One reason I believe that the analogy is valid -- and therefore that
>creation/deletion is independent of modification -- is the behavior of
>local variables.  There is absolutely no question that it is legal to
>deallocate a local variable, even if it is const:
>
> {
> const int* p;
> {
> const int x = 3;
> p = &x;
> }
> }
[...]

But *you* are not deallocating x in this example.  The compiler is
generating code to destroy the object, to which x refers.  If you were to
write to invoke a destructor x.~int(), it would be a different matter.

A way of understanding const locals and statics is to see yourself as a
client of compiler-owned objects which you have only limited access to.  On
entry into the block the compiler generates an object (non-const), allows
you *const* access to the object under the name you chose, and on exit from
the block deletes the (non-const) object.

Example:

Programmer writes:
{
    SomeClass const myObject;
    ..do something with myObject..
}

Compiler transforms this into:
{
   SomeClass __myObject;
   __usercode(__myObject);
}
void __usercode(SomeClass const& myObject)
{
   ..do something with myObject..
}

For the most part this transformation is semantically neutral, and yet, the
const auto has disappeared.

The same view can be applied to const members:  That the real member is a
hidden non-const, but what you see under the name you chose for the member
is just a const reference to the real thing.

Under this view, all real objects are non-const, but sometimes we only see
them as const.

- Anders
(The meaning of "42.~int();" is left as an exercise to the galactic
traveler.)





[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/16
Raw View
On 15 Sep 1999 15:56:40 GMT, James.Kanze@dresdner-bank.com
>In article <slrn7trsa1.uk7.sbnaran@localhost.localdomain>,

>> Even within the current rules, a std::container<const T> is improper.


>> As static_cast cannot be used to add or remove const qualifiers, the
>> cast is illegal.
>
>What makes you say that? According to 5.2.9/6: "The inverse of any
>standard conversion sequence, other than the lvalue-to-rvalue,
>array-to-pointer, function-to-pointer, and boolean conversions, can be
>performed explicitly using static_cast subject to the restriction that
>the explicit conversion does not cast away constness."  Since int const*
>to void* is a standard conversion, and void* to int const* doesn't cast
>away const, it would seem legal.  (As an aside, I wonder whether the
>standard isn't missing something about casting away volatile, as well.
>int* to volatile void* is legal, but I hope that static_cast< int* >(
>volatile void* ) isn't.)

Did you make a typographical error?  You say that "int const *" to
"void *" is a standard conversion.  Sounds to me like it should be an
error.  When I do "void * v=(int const *)0;", one of my compilers
(egcs) gives a warning and another gives an error (como EDG).

I read item 1 and it says that static_cast cannot be used to cast
away constness.  Though it seems that static_cast can be used to add
const.  Incidentally, neither of my two compilers allow it --
"int const * i=static_cast<int const *>((void*)0)" is an error.

I don't think static_cast should be allowed to add const because
there is no reason to allow it to do so.  We already have the
implicit cast and const_cast for this purpose.



>> The call to placement new is illegal as it tries to modify a read-only
>> location.
>
>No.  There is no such thing as a read-only location for a constructor --
>if an implementation does arrange to turn on write protection for
>individual objects, it must arrange for it to be turned off during
>constructors and destructors.  (At present, I know of no implementation
>which will put an object with user-defined constructors or destructors
>in write protected memory.)
>
>However, placement new takes a void*, and there is no implicit
>conversion from T const* to void*, only to void const*.  So this
>effectively fails.

Right.



>I seem to remember a special exception for this case -- a reference to a
>reference resolves to a reference to the referred to object.

   template <class In, class Out>
   struct Silly_t { void show(In &); void show(In const &); };

   template <class In, class Out>
   void Silly(Out (*func)(In), In & in) { Silly_t<In,Out>().show(in); }

   void f(int &);
   int main() { int i=0; Silly(&f,i); }

If a reference to a reference is an error, then the instantiation
   void Silly(void (*func)(int&), int & & in) { ... }
is an error.

If a reference to a reference is a reference, then the instantiation
of function Silly is ok, but the instantiation of Silly_t is not.
   struct Silly_t<void,int&> { void show(int & &); void show(int & const &); };
Both functions are the same function, hence a redeclaration error.



>As far as I can tell, this implementation is non-conforming; the
>standard requires calling ::operator delete.  But since the argument
>type is still void*, and int const* does *not* convert implicitly to
>void*, the problem remains unchanged.

I'm not clear on this distinction between standard conversion and
implicit conversion.



>Anyway, I think you've effectively proven that templates using separate
>allocation and construction cannot be instantiated on a const type
>unless they contain explicit const_cast's.

Or you specify the allocator, eg:
   std::container<const int,std::allocator<int>> c;
I'm not sure if this will work though, and I don't want to think about
it either :).

--
--------------
siemel b naran
--------------


[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/13
Raw View
In article <memo.19990911161247.39001C@btinternet.com>, Dave Harris
<scorp@btinternet.com> writes
>That code has an explicit type-cast, albeit hidden in the deleter
>function. The ability to use a const_cast does not make const useless. The
>idea is that you can break the rules, but you have to be explicit about
>it. The code is safe by default and you can, for example, trivially search
>for const_cast<>s to find possibly unsafe code.

However deleter() might well be shipped as object code in which case you
no longer have source to search.  Personally I am very unhappy at any
use of const_cast<> that allows some process that is not known to be
safe.  IOWs whenever you use const_cast<> it should be to remove a const
that has been acquired during some process of parameter passing though
the original object was not so protected.  Removing const from an object
that was defined as such is always deeply suspect.

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/09/13
Raw View
In article <37DB2E5D.89453410@ihug.co.nz>,
Ross Smith  <ross.s@ihug.co.nz> wrote:

>> The question is not whether new(const foo) is useful, but rather
>> whether new T is useful, where T is a template parameter that
>> happens to be bound to const foo.

>Well, is it? Can you give an example -- I mean a realistic example where
>it's actually useful, not just some toy code that uses it?

I can, but I won't -- because writing examples that go beyond toy
code is hard work.  What I will do is sketch the form that
such an example might take.

Consider a container class:

 template<class T> class Container {
 // ...
 };

that works by allocating and deallocating objects of type T.

The question is how much work the author of this class has to do
in order to enable a Container<const T> to work properly.

I think that if you fill in the details of this sketch, you will
understand the problem.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: ark@research.att.com (Andrew Koenig)
Date: 1999/09/13
Raw View
I'll be out of town during the coming week (if you're curious, visit
http://www.accu.org/events/public/jacc99sep.htm), so I won't be able
to participate in this discussion for a while.  Before I go, I'd like
to explain my current thinking on the delete-of-const issue.

The fundamental fact on which my thinking rests is that there is a
distinction between an object and the contents of the object, and that
it is possible to define operations on either one independently of
the other.  In particular, allocation and deallocation are something
you do to an object, and modification is something you do to the
value of the object.

The Unix file system is a fine example of a design that makes this
distinction explicit.  For example, files do not have names -- it is
only links that have names.  There is no such operation as deleting a
file -- the closest equivalent is removing a link, and doing so does
not delete the file if any other links exist to it.  Moreover, you do
not need write permission on a file in order to remove a link to it --
all you need is write permission on the directory that contains the
link.

So the Unix file system allows you to have files that you can
``remove'' but not modify, or files that you can modify but not
remove, or both, or neither.

If C++ had built-in garbage collection, the analogy to the Unix file
system would be clearer, because then delete would presumably only
invalidate the pointer, and the garbage collector would take care of
the object later.  Nevertheless, I believe that the analogy still
operates.

One reason I believe that the analogy is valid -- and therefore that
creation/deletion is independent of modification -- is the behavior of
local variables.  There is absolutely no question that it is legal to
deallocate a local variable, even if it is const:

 {
  const int* p;
  {
   const int x = 3;
   p = &x;
  }
 }

In this example, we have created a const object, placed its address in
a pointer, and then deallocated the object, leaving the pointer
invalid -- even though it is a pointer to const.

As another example, there is no question that it is legal to delete a
dynamically allocated object that contains a const member:

 class X {
 public:
  X(): a(42) { }
 private:
  const int a;
 };

 int main()
 {
  X* xp = new X;
  delete xp;
 }

Here, "delete xp;" deallocates a const object, namely member `a' of
the object that was allocated by `new X'.  Again, there is no question
that this is legal, because if it were not, there is no cast that
could render it so.

So then why is there even a question?  The most common argument I have
heard is that it is useful to be able to guarantee, for example, that
a function will not deallocate the object to which one of its
arguments points.  So, for example,

 extern void f(const T*);

It would be nice to be able to look at that definition and see that
not only will f not modify the object to which its argument points,
but it won't delete that object either.

Moreover, I agree with that argument!  It *would* be nice!  So why do
I continue to think that the committee did the right thing to make
this guarantee impossible to offer?

The reason is that I think that if such a guarantee is tied to `const',
it isn't strong enough to be useful.  In particular, as long as there
is no way to define a function that *can* modify the object it is
given, but *cannot* delete it, I consider such a guarantee to be of
limited practical value.

In other words, I want to be able to call a function such as

 X x;
 read(cin, &x);

and be able to declare `read' in such a way as to be confident that it
will not delete x, even though it can modify it.

To make this discussion more concrete, let me imagine an addition to
the language that would do what I think is necessary for such a
guarantee to be genuinely useful.  I will add a new property of
objects, analogous to `const' and `volatile', that, when present,
indicates that the object can be deleted with `delete'.  For want of a
better term, I will call this property `dynamic'.

As with `const' and `volatile', `dynamic' will have to propagate
through the type system.  Obviously the only objects that will be
`dynamic' are those allocated by `new'.  Moreover, there will be a
conversion from `dynamic T*' (i.e. pointer to `dynamic T') to T*, but
not the other way around.  So, for example:

 {
  T* tp;
  dynamic T* dtp;
  T t;

  tp = &t;  // OK
  dtp = &t;  // error -- attempt to convert
     // T* to dynamic T*
  dtp = new T;  // OK
  tp = dtp;  // OK
  delete dtp;  // OK
  delete tp;  // error -- *tp not dynamic
 }

Clearly, any arithmetic on a pointer would drop the dynamic property
from the result, as would converting a pointer to any other type --
except for derived-to-base conversion where the base had a virtual
destructor.

Given this property, it should be clear that

 extern void f0(T*);     // modify, no delete
 extern void f1(const T*);    // neither modify nor delete
 extern void f2(dynamic T*);    // both modify and delete
 extern void f3(const dynamic T*);  // delete, no modify

are all meaningful, and it is possible to imagine circumstances in
which any of them might be useful.

Well, enough hypothetical design.  C++ doesn't have `dynamic'.  So the
question about whether to allow delete of a const pointer boils down
to this question:

 Should we say that `const' implies not `dynamic' ?

If you like, we have four functions that we might like to be able to
declare, but only one bit to express which one we are declaring.
An answer of yes implies that we can declare f1 and f2, but not f0 and
f3.  An answer of no implies that we can declare f2 and f3, but not f0
and f1.  (not f0 because without `dynamic' as a language feature, we
have to behave as if it is present by default, otherwise we could
never delete any objects at all).

In other words, without `dynamic' as part of the language, we can
always declare f2, and we can never declare f0.  The question boils
down to whether it is more useful to be able to declare f1 or f3.

My answer is that it more useful to be able to declare f3, and that if
I cannot declare f0, I find little utility in being able to declare f1.
It is certainly possible to design the language so as to allow f1 and
not f3, but ultimately I think it comes down to a matter of which
tradeoff one prefers, and I continue to prefer the ability to define
f2 to the ability to define f1.

I continue to think that this is an issue about which reasonable
people can disagree.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ 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: zivca@netvision.net.il (Ziv Caspi)
Date: 1999/09/13
Raw View
On 12 Sep 99 02:59:32 GMT, ncm@nospam.cantrip.org (Nathan Myers)
wrote:

>Valentin Bonnard  <Bonnard.V@wanadoo.fr> wrote:
>>Ross Smith wrote:
>>
>>> Does
>>> anyone have any practical use for new(const foo)?
>>
>>Maybe to create a const instance. Does anybody have
>>any use of auto const Foo foo; // Foo is a UDT
>
>You make a const auto object to bind const& arguments to.

But you don't have to. You can just as easily bind const& to
a non-const auto variable. Creation of const auto variables
just relieves you of the need to bind const references
to them to disallow their change, which is not needed for
new'd objects (as you'd have to bind to a reference
anyway).

So, Valentin's question still stands: What is the use of
auto const variables?

[...]

---------------------------------------------
Ziv Caspi
zivca@netvision.net.il


[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/09/13
Raw View
francis@robinton.demon.co.uk (Francis Glassborow) wrote:
> However deleter() might well be shipped as object code in which case you
> no longer have source to search.  Personally I am very unhappy at any
> use of const_cast<> that allows some process that is not known to be
> safe.  IOWs whenever you use const_cast<> it should be to remove a const
> that has been acquired during some process of parameter passing though
> the original object was not so protected.  Removing const from an object
> that was defined as such is always deeply suspect.

I agree. Deleter() is a dangerous function to have around. I wouldn't want
it habitually used by template authors.

Deleter at least has the virtue that it can only delete, and we can search
for it at the same time we search for const_cast. Even with all its
problems I think it is better than the current situation in which the
const_cast is supplied silently by the compiler. I also don't think it
would be needed often. Eg I don't think any of my current code would need
it.

Are you aware of the other, less general but more safe idioms that have
been suggested? For example, wrapper classes like:

    template <typename Type>
    class ConstPtr {
        Type *p;
    public:
        ConstPtr( Type *pp ) : p(pp) {}
        ~ConstPtr() { delete p; }

        const Type &operator*() { return *p; }
        const Type *operator->() { return p; }
    };

Thus replace:
    const int *p( new int( 42 ) );
    delete p;

with:
    ConstPtr<int> p( new int( 42 ) );

The non-const pointer is never exposed, but kept behind the scenes for use
in the delete expression. It is type-safe; there are no casts.

Admittedly helpers like this aren't always enough. We could do with a
general mechanism for stripping the top-level const off a type. Meanwhile
we could just write more template specialisations and/or be careful about
how we instantiate them, and use deleter() as a last-ditch fall-back.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."


[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/09/13
Raw View
ark@research.att.com (Andrew Koenig) wrote:
> Consider a container class:
>
>  template<class T> class Container {
>  // ...
>  };
>
> that works by allocating and deallocating objects of type T.
>
> The question is how much work the author of this class has to do
> in order to enable a Container<const T> to work properly.

I'm not convinced such a thing makes sense. In the same way that if I
wrote:

    class X {
    private:
        ~X();
    };

I would not expect to be allowed Container<X>. However, if the thing does
make sense, we can accomplish it with a different template:

    template<typename T>
    class ConstContainer {
    public:
        const T &operator[]( int i ) const;
        //...
    };

which always adds a "const" to every T it exposes. This is a little extra
work, admittedly, but at least we can define one container in terms of the
other using inheritance.

Another approach is to use a wrapper class for T. I posted an example a
few hours ago.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."


[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/09/14
Raw View
ark@research.att.com (Andrew Koenig) wrote:
>  extern void f0(T*);     // modify, no delete
>  extern void f1(const T*);    // neither modify nor delete
>  extern void f2(dynamic T*);    // both modify and delete
>  extern void f3(const dynamic T*);  // delete, no modify
> [...]
> The question boils down to whether it is more useful to be able
> to declare f1 or f3.
>
> My answer is that it more useful to be able to declare f3, and that if
> I cannot declare f0, I find little utility in being able to declare f1.
> It is certainly possible to design the language so as to allow f1 and
> not f3, but ultimately I think it comes down to a matter of which
> tradeoff one prefers, and I continue to prefer the ability to define
> f2 to the ability to define f1.

I agree with most of your view, but at this point we depart company. To me
f3 is obscure. I am not allowed to access the object after f3 has deleted
it, so why should I care if f3 modifies it first? I won't be able to see
the change.

f1, on the other hand, would be tremendously useful. In virtually every
place where I declare a const argument, my intended meaning is "neither
modify nor delete", as f1.

I agree f0 would be nice. In truth, deletion is quite a rare thing and
most of my functions are like f0 or f1. However, I don't see that it's
essential. I don't understand why the lack of f0 makes f1 useless. Given
that we must have f2 and can only have 1 other, I'd opt for f2 and f1.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."
---
[ 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: Ross Smith <ross.s@ihug.co.nz>
Date: 1999/09/14
Raw View
Andrew Koenig wrote:
>
> Consider a container class:
>
>         template<class T> class Container {
>         // ...
>         };
>
> that works by allocating and deallocating objects of type T.
>
> The question is how much work the author of this class has to do
> in order to enable a Container<const T> to work properly.

Why would you expect a Container<const T> to work properly? I wouldn't.

To me this looks like a solution in search of a problem. You're just
pushing the "what use is it?" question back one layer of indirection.
What use is deleting const objects? Well, you need it to make containers
of const objects work. OK then, what use are containers of const
objects?

There have been several arguments in this thread along the lines of "if
you can delete a const foo* then you can do X", but none of them, to me
at least, have satisfactorily explained why you would want to do X.

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
  "There are many technical details that make Linux attractive to the
  sort of people to whom technical details are attractive."   -- Suck
---
[ 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: Jeff Rife <wevsr@nabs.net>
Date: 1999/09/14
Raw View
Andrew Koenig (ark@research.att.com) wrote:

> [excellent analogy and summary snipped]
>
>  extern void f0(T*);     // modify, no delete
>  extern void f1(const T*);    // neither modify nor delete
>  extern void f2(dynamic T*);    // both modify and delete
>  extern void f3(const dynamic T*);  // delete, no modify

And, to jump in before people say, "yeah, dynamic...that's what we
need...let's get ready for when we can revise the standard", we,
unfortunately, cannot have it.

Since what we declare now as f0 above works like the f2 above (we can,
after all, modify and delete something declared as just a T*), we
would have to add a keyword to the language that would do the opposite
of Andrew's very insightful "dynamic".

I'm going to duck as I completely jokingly suggest that we generate
yet another overload of the keyword "static", and use:

extern void f0(T*);                 // both modify and delete
extern void f1(const T*);           // delete, no modify
extern void f2(static T*);          // modify, no delete
extern void f3(const static T*);    // neither modify nor delete

--
Jeff Rife                   | "Hello.  My name is Inigo Montoya.  You killed
19445 Saint Johnsbury Lane  |  my father.  Prepare to die."
Germantown, MD  20876-1610  |
Home: 301-916-8131          |              -- Inigo Montoya, "The Princess Bride"
Work: 301-770-5800 Ext 5335 |
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/14
Raw View
Ziv Caspi <zivca@netvision.net.il> wrote:
> ncm@nospam.cantrip.org (Nathan Myers) wrote:
>>Valentin Bonnard  <Bonnard.V@wanadoo.fr> wrote:
>>>Ross Smith wrote:
>>>
>>>> Does
>>>> anyone have any practical use for new(const foo)?
>>>
>>>Maybe to create a const instance. Does anybody have
>>>any use of auto const Foo foo; // Foo is a UDT
>>
>>You make a const auto object to bind const& arguments to.
>
>But you don't have to. You can just as easily bind const& to
>a non-const auto variable.

It is in fact _not_ "just as easy" to bind a const& to a
non-const auto variable.

Suppose you have functions declared as follows:

  void f(T&);
  void f(T const&);

and you want to call the second one.

You fill in the blanks.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/14
Raw View
In article <MPG.12479407521084d9896ef@news.nabs.net>, Jeff Rife
<wevsr@nabs.net> writes
>Since what we declare now as f0 above works like the f2 above (we can,
>after all, modify and delete something declared as just a T*), we
>would have to add a keyword to the language that would do the opposite
>of Andrew's very insightful "dynamic".
>
>I'm going to duck as I completely jokingly suggest that we generate
>yet another overload of the keyword "static", and use:
>
>extern void f0(T*);                 // both modify and delete
>extern void f1(const T*);           // delete, no modify
>extern void f2(static T*);          // modify, no delete
>extern void f3(const static T*);    // neither modify nor delete

And this would be far from the first time that we have had to provide a
keyword for the reverse concept (explicit springs to mind)


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/14
Raw View
Valentin Bonnard  <Bonnard.V@wanadoo.fr> wrote:
>Nathan Myers wrote:
>> Valentin Bonnard  <Bonnard.V@wanadoo.fr> wrote:
>> >Ross Smith wrote:
>> >
>> >> Does
>> >> anyone have any practical use for new(const foo)?
>> >
>> >Maybe to create a const instance. Does anybody have
>> >any use of auto const Foo foo; // Foo is a UDT
>>
>> You make a const auto object to bind const& arguments to.
>
>You can do that with a non const object as well:
>
>Foo foo;
>const Foo& ref = foo;

_ref_ above is not an argument.  Please re-read.

The question was whether it was useful to make a const auto
object.  The answer was, yes, it is useful: it is easier to
bind const& arguments to them.  Any further quibbling is
silly; it's useful to make pointers-to-const, and it's
useful to make const auto objects.  Enough said.

>The reasons for making auto objects of UDT const and
>dynamic objects const are basically the same.

False.  There is no dynamic object without a pointer.  In use,
it is the declaration of the pointer that matters, not of the
object itself.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/14
Raw View
Dave Harris <brangdon@cix.co.uk> wrote:
>Deleter() is a dangerous function to have around. I wouldn't want
>it habitually used by template authors.
>
>Deleter at least has the virtue that it can only delete, and we can search
>for it at the same time we search for const_cast. Even with all its
>problems I think it is better than the current situation in which the
>const_cast is supplied silently by the compiler.

In discussing this we should not lose sight of the fact that deleter<>()
was introduced as a demonstration that the breaking const didn't buy
anything.  Of course the existence of a deleter template (as such)
in real code should set off alarm bells.

I would expect to see the const_cast<> at an appropriate place in
a well-designed resource-management apparatus, so there would
be no question of its correctness.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/14
Raw View
On 13 Sep 1999 16:17:06 GMT, Andrew Koenig <ark@research.att.com> wrote:

>The question is how much work the author of this class has to do
>in order to enable a Container<const T> to work properly.

Even within the current rules, a std::container<const T> is improper.

Consider
   std::container<const int> v(3,0);
which creates a container of 3 elements, each initialized to '0'.


I.

To find space for 3 elements, the container calls the default
allocator's allocate function.  In template form, it is

   T * allocator<T>::allocate(size_type N) {
      return static_cast<T *>(std::malloc(N*sizeof(T)));
   }

For T=="int const", it is

   int const * allocator<int const>::allocate(size_type N) {
      return static_cast<int const *>(std::malloc(N*sizeof(int const)));
   }

As static_cast cannot be used to add or remove const qualifiers, the
cast is illegal.



II.

To construct each element, the container calls the default allocator's
construct function.  In template form, it is

   void allocator<T>::construct(T * place, const T& obj)
   {
      new (place) T(obj);
   }


For T=="int const", it is

   void allocator<int const>::construct(int const * place, const const int& obj)
   {
      new (place) (const int)(obj);
   }

The call to placement new is illegal as it tries to modify a read-only
location.

The compiler must ignore two consts in a row in implicit template
instantiation, so the declaration is legal.  Incidentally, this means
that the following two functions are the same

   typename allocator<T>::      pointer allocator<T>::address(      reference);
   typename allocator<T>::const_pointer allocator<T>::address(const_reference);

Thus the rule that the compiler must ignore two consts in a row could
be an error in the standard.  If it is an error, then the declaration
is illegal too.

(BTW, there was an issue that in expressions like
std::bind2nd(std::mem_fun(&X::show),std::cout) we end up with a
reference to a reference.  For example, because the function show
is X::show(std::ostream&), the constructor of std::binder2nd is
   std::binder2nd::binder2nd(const Oper&, const std::ostream& &);
Forcing a reference to a reference to be a reference may cause
problems as above.)



III.

To destroy the 3 elements, the container calls the default
allocator's destroy function.  In template form, it is

   void allocator<T>::destroy(T * obj) { obj->~T(); }

For T=="int const", it is

   void allocator<int const>::destroy(int const * obj) { obj->~T(); }

It seems to me that this should be illegal, but by the current rules
of C++, it is legal.



IV.

To deallocate the 3 elements, the container calls the default
allocator's deallocate function.  In template form, it is

   void allocator<T>::deallocate(T * array) { std::free(array); }

For T=="int const", it is

   void allocator<int const>::deallocate(int const * array) {std::free(array);}

This is an error because the single argument of std::free is a "void *".

--
--------------
siemel b naran
--------------


[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/14
Raw View
In article <37DD73C6.62A4752F@ihug.co.nz>, Ross Smith <ross.s@ihug.co.nz> wrote:

> Andrew Koenig wrote:
> >
> > Consider a container class:
> >
> >         template<class T> class Container {
> >         // ...
> >         };
> >
> > that works by allocating and deallocating objects of type T.
> >
> > The question is how much work the author of this class has to do
> > in order to enable a Container<const T> to work properly.
>
> Why would you expect a Container<const T> to work properly? I wouldn't.

You could insert objects into it and remove them. You couldn't modify them
in-place. Seems reasonable enough to me.

> To me this looks like a solution in search of a problem. You're just
> pushing the "what use is it?" question back one layer of indirection.
> What use is deleting const objects? Well, you need it to make containers
> of const objects work. OK then, what use are containers of const
> objects?

Not that I consider this a real problem. Just use delete_const() to delete
the freestore.

    template<typename T>
    inline void delete_const( T const* p ) {
        delete const_cast<T*> (p);
    }

> There have been several arguments in this thread along the lines of "if
> you can delete a const foo* then you can do X", but none of them, to me
> at least, have satisfactorily explained why you would want to do X.

Right.

I'm retracting any opinion on this matter now. I can only begin to imagine
what the discussions must have been like on the committee :-)


[ 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: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/11
Raw View
Ross Smith wrote:

> Does
> anyone have any practical use for new(const foo)?

Maybe to create a const instance. Does anybody have
any use of auto const Foo foo; // Foo is a UDT

--

Valentin Bonnard


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/12
Raw View
Salters  <salters@lucent.com> wrote:
>Nathan Myers wrote:
>> Andrew Koenig <ark@research.att.com> wrote:
>> > ...  I should be able to say
>> >       template<class T> void f() {  T* tp = new T; delete tp; }
>>
>> ...before the "fix" that broke const it was trivial to write a template
>> function to delete the object:
>>
>>   template <class T> void deleter(T const* tp)
>>      { delete const_cast<T*>(tp); }
>>
>> Thus, it was already allowed to destroy any object one created.
>
>> "const" has always created inconveniences in coding, and some
>> very smart people have argued for making it a no-op.  Still, it
>> is surprising to find Andrew arguing their side.
>
>I'm wondering about this "solution".  Currently, delete can be used
>to delete a const T (given a const T *). The proposal apparently is to
>make this illegal, and then providing a loophole via deleter().

deleter<>() was not promoted as a "solution".  It is a demonstration.
There is no proposal, especially for any kind of "loophole".

The discussion is about a committee decision which broke the previously
consistent semantics of const.  deleter<>(), which has always been
possible, demonstrates that the decision failed to add any new
capability in the language.

This is unfortunate, as only a large corresponding improvement to the
language could have justified breaking const semantics.  The reason
for discussing this ancient history here is that every time it comes
up, otherwise clear-headed people prove they are not thinking clearly
about the issue.

It distresses me to see the same few logically-unsound arguments being
posted time after time.  What is it about this issue that causes people
to post obviously unsound arguments?

>I do find const sometimes annoying, especially in combination with the
>STL, but this is not one of the areas where I curse it (away).

Const is annoying because it's supposed to be annoying.  You are not
being annoyed in this area because const has already been broken.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: scorp@btinternet.com (Dave Harris)
Date: 1999/09/12
Raw View
salters@lucent.com (Salters) wrote:
> How is this an advantage, when
>
> void f(const int* pi) {
>  deleter(pi);
> }
>
> does the same, but is legal ?

That code has an explicit type-cast, albeit hidden in the deleter
function. The ability to use a const_cast does not make const useless. The
idea is that you can break the rules, but you have to be explicit about
it. The code is safe by default and you can, for example, trivially search
for const_cast<>s to find possibly unsafe code.

Compare with the situation for normal methods:

    template <typename T>
    void caller( const T *p ) {
        const_cast<T*>(p)->method();
    }

    class Object {
    public:
        void method();
        //...
    };

    void f( const Object *pObj ) {
        pObj->method();       // error; const object.
        caller( pObj );       // OK.
        const_cast<T*>(pObj)->method();  // Also Ok.
    }

You can't call the non-const method directly on a const object, but you
can if you use a cast or a function that uses a cast. Same thing.

Deleter() is not a special magic; it was brought up only because the
explicit cast, as in the 3rd line of f() above, is not always convenient
when writing templates.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."
---
[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/12
Raw View
Valentin Bonnard  <Bonnard.V@wanadoo.fr> wrote:
>Ross Smith wrote:
>
>> Does
>> anyone have any practical use for new(const foo)?
>
>Maybe to create a const instance. Does anybody have
>any use of auto const Foo foo; // Foo is a UDT

You make a const auto object to bind const& arguments to.

The analogous process doesn't apply to new'd objects, because
new doesn't return the object, but a pointer to it:

  {
    const Foo foo;
    f(foo);   // template <class T> void f(T const&);
    Foo const* fp = new Foo;
    f(*fp);
  }

This is not to say that a closer analogy could not be constructed;
rather, that argument by analogy is unlikely to lead anywhere
meaningful.  Consider consequences, and you may make progress.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: Ross Smith <ross.s@ihug.co.nz>
Date: 1999/09/12
Raw View
Andrew Koenig wrote:
>
> In article <37D8973E.65CDE27D@ihug.co.nz>,
> Ross Smith  <ross.s@ihug.co.nz> wrote:
>
> >For const objects, I would have thought it made more sense to fix the
> >asymmetry by disallowing creation than by allowing destruction. Does
> >anyone have any practical use for new(const foo)?
>
> Every restriction that applies to some types but not others
> makes it harder to write useful templates.
>
> The question is not whether new(const foo) is useful, but rather
> whether new T is useful, where T is a template parameter that
> happens to be bound to const foo.

Well, is it? Can you give an example -- I mean a realistic example where
it's actually useful, not just some toy code that uses it?

I don't see why the inability to use new is any more of a handicap than
the inability to call a non-const member function, or to use it on the
LHS of an assignment, or anything else that const objects can't do.

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
  "There are many technical details that make Linux attractive to the
  sort of people to whom technical details are attractive."   -- Suck


[ 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: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/13
Raw View
Nathan Myers wrote:
>
> Valentin Bonnard  <Bonnard.V@wanadoo.fr> wrote:
> >Ross Smith wrote:
> >
> >> Does
> >> anyone have any practical use for new(const foo)?
> >
> >Maybe to create a const instance. Does anybody have
> >any use of auto const Foo foo; // Foo is a UDT
>
> You make a const auto object to bind const& arguments to.

???

You can do that with a non const object as well:

Foo foo;
const Foo& ref = foo;

The reasons for making auto objects of UDT const and
dynamic objects const are basically the same.

--

Valentin Bonnard
---
[ 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: Salters <salters@lucent.com>
Date: 1999/09/10
Raw View
Nathan Myers wrote:
>
> Andrew Koenig <ark@research.att.com> wrote:
> >The argument that I consider the strongest, and to which I have
> >never seen a counterargument that is the least bit convincing,
> >is that if you are allowed to create an object, you should be
> >allowed to destroy it.
> >That is ...  I should be able to say

> >       template<class T> void f() {  T* tp = new T; delete tp; }

> >...  However,
> >this argument has not been demolished, and if I have appeared to
> >drop the subject, it is only because there is a limit to how many
> >times I am willing to repeat myself in the absence of new evidence.

> Andrew has indeed posted this example repeatedly.

> I have not seen any reply from Andrew when it was pointed out that
> before the "fix" that broke const it was trivial to write a template
> function to delete the object:

>   template <class T> void deleter(T const* tp)
>      { delete const_cast<T*>(tp); }

> This allowed f() to be written:

>   template<class T> void f() {  T* tp = new T; deleter(tp); }

> Thus, it was already allowed to destroy any object one created.

> Of course, after breaking const, the committee then broke the
> equivalence of "new T" and "new const T", perhaps (it's not clear)
> rendering the call to the deleter template above undefined.

> "const" has always created inconveniences in coding, and some
> very smart people have argued for making it a no-op.  Still, it
> is surprising to find Andrew arguing their side.

> --
> Nathan Myers

I'm wondering about this "solution". Currently, delete can be used to
delete a const T (given a const T *). The proposal apparently is to
make this illegal, and then providing a loophole via deleter().

This would guarantee that a function would not call delete on a
pointer to const that is passed. E.g.

void f(const int* pi) {
 delete pi;
}

would be illegal. How is this an advantage, when

void f(const int* pi) {
 deleter(pi);
}

does the same, but is legal ?

I fail to see the advantage. This just changes the syntax required to
delete a pointer. The only way a client could find out (under the new
rules) if a pointer to const is deleted, is to look to the source of
the function. But this is exactly the problem the solution was intended
to solve. Therefore I'm inclined to conclude this is a non-solution.

I do find const sometimes annoying, especially in combination with the
STL, but this is not one of the areas where I curse it (away).

Michiel Salters


[ 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: Ross Smith <ross.s@ihug.co.nz>
Date: 1999/09/10
Raw View
Andrew Koenig wrote:
>
> The argument that I consider the strongest, and to which I have
> never seen a counterargument that is the least bit convincing,
> is that if you are allowed to create an object, you should be
> allowed to destroy it.

For const objects, I would have thought it made more sense to fix the
asymmetry by disallowing creation than by allowing destruction. Does
anyone have any practical use for new(const foo)?

--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
  "There are many technical details that make Linux attractive to the
  sort of people to whom technical details are attractive."   -- Suck
---
[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/09
Raw View
On 8 Sep 1999 16:18:24 GMT, Darin Adler <darin@bentspoon.com> wrote:
>Siemel B. Naran <sbnaran@uiuc.edu> wrote:

>> One should not be able to delete a pointer to void for the same
>> reasons as above, but the standard allows it for backward
>> compatibility with C.

>I'm not sure what you mean by backward compatibility with C, by the way,
>since there's no "delete" in C.

Sorry.  I should have set std::free(v).  I think C allows it.

--
--------------
siemel b naran
--------------


[ 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: James.Kanze@dresdner-bank.com
Date: 1999/09/09
Raw View
In article <7r5als$9cl$1@shell7.ba.best.com>,
  ncm@nospam.cantrip.org (Nathan Myers) wrote:

> Since casting away const on a really-const object results in undefined
> behavior, fixing const by restricting delete-expressions requires also
> fixing this later change, or such an object could not be deleted.

Is it casting away the const which is undefined, or actually trying to
change the object?  The way I remember it (but they may have changed
things since I looked at the issue), you could cast away const anyway
you liked, but trying to modify an object was undefined behavior if (and
only if) the object itself was const and the type contained no mutable
members.

    [...]
> >What are the arguments?  ...  Hmmm, could this have to do with a
> >template allocating an object with "new T", where T happens to be
> >const? (hope I didn't open the can of worms)

> Yes, that was Andrew Koenig's example:

>   template <typename T>
>     void f() {
>        T* tp = new T;
>        delete tp;   // oops, what if T is "const int"?
>     }

The problem with this argument (IMHO) is that it can be easily and
logically extended.  What if the template is:

    template< typename T >
    void f()
    {
        T* tp = new T ;
        *tp = 0 ;    // oops, what if T is "const int"?
        delete tp ;
    }

The answer to both is the same: if the template modifies anything of
type T (and from a pratical point of view, deleting is effectively a
modification), then don't instantiate it on a const type.

(You can make a similar analogy by stating: what if T is int&.  Yet no
one proposed being able to allocate and free references.  I hope.)

    [...]
> >What about delete for incomplete types? Is that allowed too?!?

> Believe it or don't, yes!

> The reasoning here was that people should be able to global-change
> "free(p)" to "delete p", and not allowing deletion of incomplete
> pointer types would interfere with that.  Fortunately, since it's
> always wrong to do, every compiler can warn about it.

Which is, perhaps, the correct compromise.  About the only time anyone
would make a global search and replace for free(p) is when converting C
code.  And C code won't have any destructors, inheritance, etc., which
will make deleting an incomplete type a problem.

--
James Kanze                   mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/09
Raw View
Andrew Koenig <ark@research.att.com> wrote:
>The argument that I consider the strongest, and to which I have
>never seen a counterargument that is the least bit convincing,
>is that if you are allowed to create an object, you should be
>allowed to destroy it.
>
>That is ...  I should be able to say
>
> template<class T> void f() {  T* tp = new T; delete tp; }
>
>...  However,
>this argument has not been demolished, and if I have appeared to
>drop the subject, it is only because there is a limit to how many
>times I am willing to repeat myself in the absence of new evidence.

Andrew has indeed posted this example repeatedly.

I have not seen any reply from Andrew when it was pointed out that
before the "fix" that broke const it was trivial to write a template
function to delete the object:

  template <class T> void deleter(T const* tp)
     { delete const_cast<T*>(tp); }

This allowed f() to be written:

  template<class T> void f() {  T* tp = new T; deleter(tp); }

Thus, it was already allowed to destroy any object one created.

Of course, after breaking const, the committee then broke the
equivalence of "new T" and "new const T", perhaps (it's not clear)
rendering the call to the deleter template above undefined.

"const" has always created inconveniences in coding, and some
very smart people have argued for making it a no-op.  Still, it
is surprising to find Andrew arguing their side.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]





Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/09
Raw View
On 8 Sep 1999 19:08:47 GMT, Andrew Koenig <ark@research.att.com> wrote:

>The argument that I consider the strongest, and to which I have
>never seen a counterargument that is the least bit convincing,
>is that if you are allowed to create an object, you should be
>allowed to destroy it.

My counter-argument is that you should not be able to create a
const argument.  Instead, create a "new X" then cast the result
from "X *" to "X const *".

If you have to write a template function that creates a new
T object where T may be "X" or "X const", then use the
following helper class to remove top-level const.


template <class T>
struct no_toplevel_const { typedef T result; };

template <class T>
struct no_toplevel_const<const T> { typedef T result; };

--
--------------
siemel b naran
--------------
---
[ 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: James Kuyper <kuyper@wizard.net>
Date: 1999/09/09
Raw View
"Siemel B. Naran" wrote:
>
> On 8 Sep 1999 16:18:24 GMT, Darin Adler <darin@bentspoon.com> wrote:
> >Siemel B. Naran <sbnaran@uiuc.edu> wrote:
...
> >I'm not sure what you mean by backward compatibility with C, by the way,
> >since there's no "delete" in C.
>
> Sorry.  I should have set std::free(v).  I think C allows it.

But there's no compatibility issues between C++ 'delete' and C free(),
so that can't be a reason. new/delete and malloc()/free() can't mix.
There might have been a desire to avoid unnecessary differences, to ease
understanding of 'delete', but that's doesn't make it a compatibility
issue.

Also, there's no such thing in C as std::free().
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/09
Raw View
In article <slrn7teb6m.92n.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:

> On 8 Sep 1999 16:18:24 GMT, Darin Adler <darin@bentspoon.com> wrote:
> >Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>
> >> One should not be able to delete a pointer to void for the same
> >> reasons as above, but the standard allows it for backward
> >> compatibility with C.
> >
> >I'm not sure what you mean by backward compatibility with C, by the way,
> >since there's no "delete" in C.
>
> Sorry.  I should have set std::free(v).  I think C allows it.

Stop. Think. Then post. (I wouldn't have said this if it weren't for your
double-fault here)

C has no notion of construction and destruction. free() simply frees
memory allocated with malloc (or calloc or realloc). void* is used because
the memory can be used for anything. So yes, free() takes a void*.
---
[ 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: "Steve Downey" <downey_stephen@jpmorgan.com>
Date: 1999/09/07
Raw View

Siemel B. Naran <sbnaran@uiuc.edu> wrote in message
news:slrn7t5lq0.jgc.sbnaran@localhost.localdomain...
>
> It drives me crazy because I sometimes want an array of pointers
> to existing objects, and I don't want the user to be able to
> call delete on these pointers.  For example, suppose that I have
> a list of House objects, and I want a list of all houses that
> cost $250,000 or more.  Then I write this function
>
>    std::deque<const House *> expensive_houses(const std::list<Houses>&);
>
> I'd prefer it if clients were not able to write
>
>    std::deque<const House *> e(expensive_houses(all_houses));
>    delete e.front();
>
> Requiring the use of "const_cast<>" to delete a pointer to const
> would be an easy addition to C++.  It may be a little more
> cumbersome for people to deal with -- ie, those people who really
> must delete pointer to const objects.  It may be somewhat
> logically inconsistent, as Blargg points out above.  But it would
> make C++ just a little safer, and so it is a good thing.
>
> ---
> ---
>
> But here's something else to consider.  After I find all houses that
> are $250,000 or more, I sometimes want to modify them some way.  Then
> my function becomes
>
>    std::deque<House *> expensive_houses(std::list<Houses>&);
>
> And I still don't want users to be able to delete houses in the
> std::deque.  Only someone with the original list of houses should
> be able to delete House objects.
>
> So now you should not be able to apply delete to a pointer to any
> object!
>
>
> I have some ideas for enforcing my ideas, but I think they should be
> the subject of third-party compiler tools rather than of the language.
> Only a scope S that new's a object should be able to delete the
> object.  For example,
>    A::A() { a=new aa; }
>    A::~A() { delete a; }
>
> But then, how do we deal with create functions?  Here the create
> function (scope S2) creates an object, and the function that calls the
> create function (scope S1) deletes the object.  I guess that if the
> create function returns a std::auto_ptr<>, then the problem goes away.
>
> --
> --------------
> siemel b naran
> --------------
> ---


I think the best way of handling something like this requirement, and the
second, is to write a wrapper class. IE:
namespace wrapper
{
class House
{
House * theHouse;
double price() {return theHouse->price();}
//...
}
}
std::deque<wrapper::House> expensive_houses(const std::list<impl::House>&) ;

If you want to modify some things about the House, define the interface that
allows the mods that you want, and add that to wrapper::House.

Users of the library never touch your houses





This communication is for informational purposes only.  It is not intended as
an offer or solicitation for the purchase or sale of any financial instrument
or as an official confirmation of any transaction, unless specifically agreed
otherwise. All market prices, data and other information are not warranted as
to completeness or accuracy and is subject to change without notice. Any
comments or statements made herein do not necessarily reflect those of
J.P. Morgan & Co. Incorporated, its subsidiaries and affiliates.



[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/08
Raw View
On 07 Sep 99 19:52:22 GMT, blargg <postmast.root.admi.gov@iname.com> wrote:
>In article <7r2m1t$n61$1@shell7.ba.best.com>, ncm@nospam.cantrip.org

>What are the arguments? (feel free to e-mail them privately if you like :-)

No, you should post them to the newsgroup.


>Const was evolved for practical use in constraining what can be done to an
>object. There is no "right" way, as I see it now, for it to interact with
>object lifetime. It's whatever is most practical. This argument makes it
>clear which choice is more practical. It stands on the fundamental use of
>const - to show that something doesn't mess with soemthing else ("just
>looking").

While I think that one should not be able to delete pointer-to-const
(instead, one should you const_cast then delete), I'm not sure if it
makes a big difference.  Is anyone going to think of deleting the
pointer anyway?


>What about delete for incomplete types? Is that allowed too?!?

One cannot delete a pointer to an incomplete type because it is not
clear what destructor to call (the destructor may be virtual or
inline, but we don't know it).

One should not be able to delete a pointer to void for the same
reasons as above, but the standard allows it for backward
compatibility with C.

--
--------------
siemel b naran
--------------
---
[ 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: "Darin Adler" <darin@bentspoon.com>
Date: 1999/09/08
Raw View
Siemel B. Naran <sbnaran@uiuc.edu> wrote:

> One should not be able to delete a pointer to void for the same
> reasons as above, but the standard allows it for backward
> compatibility with C.

The standard doesn't allow you to delete a pointer to void. 5.3.5 is the
section that explains the rules for how delete works, and a footnote in the
section highlights this very point: "This implies that an object cannot be
deleted using a pointer of type void* because there are no objects of type
void."

However, since 5.3.5 says the behavior is undefined, a compiler is allowed
to accept "delete x" where x is a void* and do anything and still be
conforming. A conforming compiler could issue an error message or a warning.
Another conforming compiler could successfully delete the object.

I'm not sure what you mean by backward compatibility with C, by the way,
since there's no "delete" in C.

    -- Darin


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/08
Raw View
blargg <postmast.root.admi.gov@iname.com> wrote:
> ncm@nospam.cantrip.org (Nathan Myers) wrote:
>> blargg <postmast.root.admi.gov@iname.com> wrote:
>> > I am quite aware of the differences [between a const object
>> > and the referent of a pointer-to-const] ...
>> > I just don't see object lifetime as being connected to
>> > const-ness (though I'm wide open to have my view changed with convincing
>> > arguments).
>[snip]
>> In other words, if constness and object lifetime are indeed unrelated,
>> then we should be discussing only the purpose of constness itself and
>> whether allowing the delete-expression is consistent that purpose.
>
>That does it :-)
>
>There is a common dichotomy that I encounter when considering what
>something should do. It is between theory and practice. This is something
>that C++ has really taught me much about. So far, my arguments have been
>theoretical mainly. They have dealt with concept clarity and
>orthogonality.
>
>> > My quoted statement above assumes no casting. Obviously one can cast
>> > to a non-const pointer type prior to deletion.
>>
>> Or one can retain a pointer-to-non-const for use in deletion.
>> Either is easily encapsulated by the owner of the object, and
>> need not be visible to clients.
>
>Right. new const T is really new T, then convert to const T*. new const T
>should be meaningless. Just allocate with new T and use const T* to
>enforce the const restriction.

Unfortunately, text has been added to muddle this point.  It is now
possible, in principle, to create an actually-const object on the free
store -- even though there is only one operator new() (which returns
non-const void*) to allocate storage for it.

Since casting away const on a really-const object results in
undefined behavior, fixing const by restricting delete-expressions
requires also fixing this later change, or such an object could not
be deleted.

>> >> More interesting than the original question is why this issue
>> >> drives so many people off the rails, and what it shares with
>> >> other issues with the same effect.  Such issues arising in
>> >> language design are very dangerous, and need to be identified
>> >> early.
>> >
>> > Can you elaborate a bit?
>>
>> I appreciate the open-mindedness; it would have been welcome when
>> the committee was in session.
>
>I consider this discussion here, and when I take the view that you are not
>open-minded on the issue, I don't consider the discussion worthwhile. I
>suppose being open-minded means that I can't determine whether you are
>closed-minded until I can see your viewpoint first. I am seeing something
>new now, and have been persuaded quite well - practicality wins :-)
>
>[snip]
>> The argument that
>> swayed most committee members appears to have been an argument by
>> analogy; the two cases
>>
>>   { const T t; }            // calls T::T(), followed by T::~T().
>>   { T const* tp = new T; delete tp; }
>>
>> were seen by many as somehow equivalent.
>
>I came up with this "equivalence" too in considering the issue for myself,
>so I am aware of its "lure".
>
>> (At the time, "new T"
>> and "new const T" were semantically identical -- the "const" was
>> effectively ignored -- although this was changed with the addition
>> of some rather mystical language very late in the process, well
>> after the "fix".)
>
>heh.
>
>> The argument was that since the compiler was obliged to call the
>> _destructor_ where the object goes out of scope, anybody should be
>> equally free to execute a _delete-expression_ there, or anywhere.
>
>Right. This is the theoretical argument, really. const isn't about theory,
>though; it's about practical use (consider the addition of mutable, for
>example).
>
>> The practical argument for breaking const in this case was that
>> it had turned out to be "inconvenient" to cast away the pointer's
>> constness before destroying the object.  That such "inconvenience"
>> is the whole point of const-correctness seemed lost on most of the
>> committee members at the time.  (Also, the vote was taken, IIRC,
>> very late in the afternoon.)
>
>Yes. I still consider the "equivalence" example to be a little unsettling,
>but const has other issues too (for example, binding a
>pointer-to-non-const using "this" in a ctor, then modifying any member of
>the object in a const member function - no cast!).
>
>> After the fact, more sophisticated but equally specious arguments
>> have arisen to justify the change, bringing in details of template
>> argument deduction.  All such arguments have been neatly disposed of.
>> (If anybody wants to try to resurrect any such arguments, I will be
>> happy to dispose of them again.)
>
>What are the arguments?  ...
>Hmmm, could this have to do with a template allocating an object with "new
>T", where T happens to be const? (hope I didn't open the can of worms)

Yes, that was Andrew Koenig's example:

  template <typename T>
    void f() {
       T* tp = new T;
       delete tp;   // oops, what if T is "const int"?
    }

demolished neatly by:

  template <typename T>
    void deleter(T const* tp) { delete const_cast<T*>(tp); }

  template <typename T>
    void f() {
       T* tp = new T;
       deleter(tp);   // OK
    }

(Of course this depends on the old equivalence of "new T" and
"new const T", which was broken shortly after const itself was
broken.)

>> Still, none of the committee members
>> who argued for breaking const has conceded the point in public, despite
>> demolition of all their arguments; each has just dropped the subject.
>>
>> The practical effect is that prior to the "fix", one could safely
>> pass or return a pointer-to-const to any function, and know that,
>> in the absence of a cast, nothing could be done to damage the object.
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> For example, one could place a sensitive resource in the object
>> pointed to, and know that it could not be stolen.
>
>And this does it for me. Weigh this against the "inconvenience" of the
>"equivalent" code example, and it tips the scales very very easily.
>
>Const was evolved for practical use in constraining what can be done to an
>object. There is no "right" way, as I see it now, for it to interact with
>object lifetime. It's whatever is most practical. This argument makes it
>clear which choice is more practical. It stands on the fundamental use of
>const - to show that something doesn't mess with something else ("just
>looking").
>
>> From a design standpoint, it should be clear to everyone that the
>> purpose of "const" on an interface is to allow the interface designer
>> to enforce invariants.  Prior to the "fix", an interface could be
>> carefully designed to release a pointer-to-const, knowing that
>> nothing (without casting) could violate its invariants.
>>
>> For example, one could write
>>
>>   T const* f() { T const* p = new T; g(p); return p; }
>>
>> and, without knowing anything about g() or about f()'s caller (except
>> that they do not use casts), know that p was still usable and returnable.
>> Now, all bets are off. Const is broken, and the best we can hope for
>> is for coding standards and compilers to warn against deleting via a
>> pointer-to-const.
>
>Thanks alot. Now I'm going to be wishing my compiler warned of deletion of
>a pointer-to-const :-)

I believe that gcc-2.95 can be persuaded to warn about it.

>> In practice, library designers, perforce, implement interfaces as if
>> the change had not happened, because to wrap every pointer up in a
>> class object just to enforce constness would be too messy.  The effect
>> is that a common error that previously was easily detected at compile
>> time is no longer easily detectable at all.
>>
>> That otherwise-careful committee members were swayed by such specious
>> arguments in this case -- as they were, also, in the case of delete-
>> expressions applied to pointers to incomplete types -- seems to me a
>> cause for deep concern.
>
>What about delete for incomplete types? Is that allowed too?!?

Believe it or don't, yes!

The reasoning here was that people should be able to global-change
"free(p)" to "delete p", and not allowing deletion of incomplete
pointer types would interfere with that.  Fortunately, since it's
always wrong to do, every compiler can warn about it.

>> Perhaps in future language design discussions,
>> the "C++ Delete-Expression Fallacies" may be invoked when reasoning
>> threatens to go off the rails.
>
>heh. Thanks for putting me back on the rails.
>
>Now, I have to ask "what else can I learn from this incident, in general,
>about language reasoning?" I will be thinking about this for a while...

Maybe, don't conduct votes in the late afternoon?

(It was also a late-afternoon (and last-day) vote that resulted in the
std::char_traits<> members getting the wrong return values, so that they
must be implemented less efficiently than was previously possible.
Hint: std::memcpy() returns the wrong value; std::copy() returns the
right one.)

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/08
Raw View
On 7 Sep 1999 21:51:21 GMT, Steve Downey <downey_stephen@jpmorgan.com> wrote:

>I think the best way of handling something like this requirement, and the
>second, is to write a wrapper class. IE:
>namespace wrapper
>{
>class House
>{
>House * theHouse;
>double price() {return theHouse->price();}
>//...
>}
>}
>std::deque<wrapper::House> expensive_houses(const std::list<impl::House>&) ;

Thanks for the idea.  It's simple, yet I never thought of it.  I don't
like the idea though because it means one new class in the project and
lots of writing forwarding functions.  But I like your twist of making
a namespace for wrapper objects.

--
--------------
siemel b naran
--------------


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/05
Raw View
blargg <postmast.root.admi.gov@iname.com> wrote:
><norbert@dune.gia.rwth-aachen.de> wrote:
>> Is the following c++ formally o.k.?
>>
>> void f (Foo const * p)  // [s/void/Foo/ -ncm]
>> {
>>   delete p;
>> }
>
>Lifetime is separate from const-ness. How else would you create a const
>object and ever hope for it to be destroyed, if destroying/deleting a
>const object were illegal?

Norbert has (again) called attention to a fundamental design
error in the language.  This is indeed a frequently raised topic,
but is very interesting in that it never fails to elicit examples
of embarrassingly specious reasoning from people who are otherwise
mostly sober and clear-headed.

Blargg's question above falls into that category, confusing
"pointer-to-const" (which may of course point at any object)
with a notional pointer-to-actually-const-object, which is not
expressible in the type system.

More interesting than the original question is why this issue
drives so many people off the rails, and what it shares with
other issues with the same effect.  Such issues arising in
language design are very dangerous, and need to be identified
early.

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.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              ]






Author: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/06
Raw View
In article <7qt8d2$ssm$1@shell7.ba.best.com>, ncm@nospam.cantrip.org
(Nathan Myers) wrote:

> blargg <postmast.root.admi.gov@iname.com> wrote:
> ><norbert@dune.gia.rwth-aachen.de> wrote:
> >> Is the following c++ formally o.k.?
> >>
> >> void f (Foo const * p)  // [s/void/Foo/ -ncm]
> >> {
> >>   delete p;
> >> }
> >
> >Lifetime is separate from const-ness. How else would you create a const
> >object and ever hope for it to be destroyed, if destroying/deleting a
> >const object were illegal?
>
> Norbert has (again) called attention to a fundamental design
> error in the language.  This is indeed a frequently raised topic,
> but is very interesting in that it never fails to elicit examples
> of embarrassingly specious reasoning from people who are otherwise
> mostly sober and clear-headed.
>
> Blargg's question above falls into that category, confusing
> "pointer-to-const" (which may of course point at any object)
> with a notional pointer-to-actually-const-object, which is not
> expressible in the type system.

I am quite aware of the differences between these two guarantees. One can
be bound to non-const objects, as const currently means, while the other
can *only* be bound to const objects (similar to the recent discussion on
a pointer to final type, meaning it can only point to an object of that
complete type). I just don't see object lifetime as being connected to
const-ness (though I'm wide open to have my view changed with convincing
arguments).

My quoted statement above assumes no casting. Obviously one can cast to a
non-const pointer type prior to deletion.

> More interesting than the original question is why this issue
> drives so many people off the rails, and what it shares with
> other issues with the same effect.  Such issues arising in
> language design are very dangerous, and need to be identified
> early.

Can you elaborate a bit?

(completely open to having all my reasoning on this matter shown to be
totally braindead)


[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/06
Raw View
On 5 Sep 1999 14:56:53 GMT, Nathan Myers <ncm@nospam.cantrip.org> wrote:
>blargg <postmast.root.admi.gov@iname.com> wrote:
>>norbert@dune.gia.rwth-aachen.de> wrote:

>>> Is the following c++ formally o.k.?
>>>
>>> void f (Foo const * p)  // [s/void/Foo/ -ncm]
>>> {
>>>   delete p;
>>> }

>>Lifetime is separate from const-ness. How else would you create a const
>>object and ever hope for it to be destroyed, if destroying/deleting a
>>const object were illegal?

>More interesting than the original question is why this issue
>drives so many people off the rails, and what it shares with
>other issues with the same effect.  Such issues arising in
>language design are very dangerous, and need to be identified
>early.

It drives me crazy because I sometimes want an array of pointers
to existing objects, and I don't want the user to be able to
call delete on these pointers.  For example, suppose that I have
a list of House objects, and I want a list of all houses that
cost $250,000 or more.  Then I write this function

   std::deque<const House *> expensive_houses(const std::list<Houses>&);

I'd prefer it if clients were not able to write

   std::deque<const House *> e(expensive_houses(all_houses));
   delete e.front();

Requiring the use of "const_cast<>" to delete a pointer to const
would be an easy addition to C++.  It may be a little more
cumbersome for people to deal with -- ie, those people who really
must delete pointer to const objects.  It may be somewhat
logically inconsistent, as Blargg points out above.  But it would
make C++ just a little safer, and so it is a good thing.

---
---

But here's something else to consider.  After I find all houses that
are $250,000 or more, I sometimes want to modify them some way.  Then
my function becomes

   std::deque<House *> expensive_houses(std::list<Houses>&);

And I still don't want users to be able to delete houses in the
std::deque.  Only someone with the original list of houses should
be able to delete House objects.

So now you should not be able to apply delete to a pointer to any
object!


I have some ideas for enforcing my ideas, but I think they should be
the subject of third-party compiler tools rather than of the language.
Only a scope S that new's a object should be able to delete the
object.  For example,
   A::A() { a=new aa; }
   A::~A() { delete a; }

But then, how do we deal with create functions?  Here the create
function (scope S2) creates an object, and the function that calls the
create function (scope S1) deletes the object.  I guess that if the
create function returns a std::auto_ptr<>, then the problem goes away.

--
--------------
siemel b naran
--------------
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/06
Raw View
In article <slrn7t5lq0.jgc.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:

> On 5 Sep 1999 14:56:53 GMT, Nathan Myers <ncm@nospam.cantrip.org> wrote:
> >blargg <postmast.root.admi.gov@iname.com> wrote:
> >>norbert@dune.gia.rwth-aachen.de> wrote:
>
> >>> Is the following c++ formally o.k.?
> >>>
> >>> void f (Foo const * p)  // [s/void/Foo/ -ncm]
> >>> {
> >>>   delete p;
> >>> }
>
> >>Lifetime is separate from const-ness. How else would you create a const
> >>object and ever hope for it to be destroyed, if destroying/deleting a
> >>const object were illegal?
>
> >More interesting than the original question is why this issue
> >drives so many people off the rails, and what it shares with
> >other issues with the same effect.  Such issues arising in
> >language design are very dangerous, and need to be identified
> >early.
>
> It drives me crazy because I sometimes want an array of pointers
> to existing objects, and I don't want the user to be able to
> call delete on these pointers.  For example, suppose that I have
> a list of House objects, and I want a list of all houses that
> cost $250,000 or more.

Well, what if you didn't want users calling function "f" on these objects?
How would you express this in the language? Maybe this too is a situation
that shouldn't be directly represented in the language. How useful a
restriction is it, in light of the myriad of other restrictions you may
also want to enforce, but can't (and for some reason aren't driven crazy
by)?

> Then I write this function
>
>    std::deque<const House *> expensive_houses(const std::list<Houses>&);
>
> I'd prefer it if clients were not able to write
>
>    std::deque<const House *> e(expensive_houses(all_houses));
>    delete e.front();
>
> Requiring the use of "const_cast<>" to delete a pointer to const
> would be an easy addition to C++.

So, in other words, you're slipping in this extra restriction just so you
don't have to add a proper restriction, perhaps "undeletable"? I don't
like having multiple semantics crammed together like this. What if you
want to express "undeletable" and "non-const"? Seems reasonable enough to
me, perhaps even in your example.

> It may be a little more
> cumbersome for people to deal with -- ie, those people who really
> must delete pointer to const objects.  It may be somewhat
> logically inconsistent, as Blargg points out above.  But it would
> make C++ just a little safer, and so it is a good thing.

I don't buy this. It seems to be in the same class as adding a laundry
list of features without any look at the overall picture.

> But here's something else to consider.  After I find all houses that
> are $250,000 or more, I sometimes want to modify them some way.  Then
> my function becomes
>
>    std::deque<House *> expensive_houses(std::list<Houses>&);
>
> And I still don't want users to be able to delete houses in the
> std::deque.  Only someone with the original list of houses should
> be able to delete House objects.

Ahhhh... told you so  :-)

> So now you should not be able to apply delete to a pointer to any
> object!
>
> I have some ideas for enforcing my ideas, but I think they should be
> the subject of third-party compiler tools rather than of the language.

While these can be useful, I personally don't like having to use extra
tools. Integration with the development environment is a big concern to
me. I don't like tedious repetitive tasks (those are for the computer to
do).

> Only a scope S that new's a object should be able to delete the
> object.  For example,
>
>    A::A() { a=new aa; }
>    A::~A() { delete a; }
>
> But then, how do we deal with create functions?  Here the create
> function (scope S2) creates an object, and the function that calls the
> create function (scope S1) deletes the object.  I guess that if the
> create function returns a std::auto_ptr<>, then the problem goes away.

This problem would be interesting to explore without constraining
ourselves to current C++.


[ 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/07
Raw View
blargg <postmast.root.admi.gov@iname.com> wrote:
> ncm@nospam.cantrip.org (Nathan Myers) wrote:
>> blargg <postmast.root.admi.gov@iname.com> wrote:
>> ><norbert@dune.gia.rwth-aachen.de> wrote:
>> >> Is the following c++ formally o.k.?
>> >>   void f (Foo const * p)  { delete p; }
>> >
>> >Lifetime is separate from const-ness. How else would you create a const
>> >object and ever hope for it to be destroyed, if destroying/deleting a
>> >const object were illegal?
>>
>> Norbert has (again) called attention to a fundamental design
>> error in the language.  This is indeed a frequently raised topic,
>> but is very interesting in that it never fails to elicit examples
>> of embarrassingly specious reasoning from people who are otherwise
>> mostly sober and clear-headed.
>>
>> Blargg's question above falls into that category, confusing
>> "pointer-to-const" (which may of course point at any object)
>> with a notional pointer-to-actually-const-object, which is not
>> expressible in the type system.
>
> I am quite aware of the differences ...
> I just don't see object lifetime as being connected to
> const-ness (though I'm wide open to have my view changed with convincing
> arguments).

The mention of "object lifetime" has been a key source of confusion
among those posting on the subject.  An object's lifetime is from
when the constructor returns until the destructor is entered.

Since the question is whether users should be allowed to apply the
delete-expression to a pointer-to-const, to mention a destructor
call, which must needs occur *after* the delete-expression, begs
the question.  It is this confusion that allowed the mistake to be
made.

In other words, if constness and object lifetime are indeed unrelated,
then we should be discussing only the purpose of constness itself and
whether allowing the delete-expression is consistent that purpose.

> My quoted statement above assumes no casting. Obviously one can cast
> to a non-const pointer type prior to deletion.

Or one can retain a pointer-to-non-const for use in deletion.
Either is easily encapsulated by the owner of the object, and
need not be visible to clients.

>> More interesting than the original question is why this issue
>> drives so many people off the rails, and what it shares with
>> other issues with the same effect.  Such issues arising in
>> language design are very dangerous, and need to be identified
>> early.
>
> Can you elaborate a bit?

I appreciate the open-mindedness; it would have been welcome when
the committee was in session.  This has been gone over before in some
detail, but with the moderators' permission, I will summarize again.

Cfront never enforced constness in contexts like:

  void f(T const* tp) { tp->T::~T(); }

for what are probably historical, and in any case formally indefensible
reasons; the destructor is certainly non-const.  A const destructor
would be meaningless, and was detected as an error by Cfront.

It was noted that Cfront did not permit "delete tp" in that context.
Rather than restricting explicit destructor calls to non-const lvalues,
the laxity was extended to the delete-expression.  The argument that
swayed most committee members appears to have been an argument by
analogy; the two cases

  { const T t; }            // calls T::T(), followed by T::~T().
  { T const* tp = new T; delete tp; }

were seen by many as somehow equivalent.  (At the time, "new T"
and "new const T" were semantically identical -- the "const" was
effectively ignored -- although this was changed with the addition
of some rather mystical language very late in the process, well
after the "fix".)

The argument was that since the compiler was obliged to call the
_destructor_ where the object goes out of scope, anybody should be
equally free to execute a _delete-expression_ there, or anywhere.

The practical argument for breaking const in this case was that
it had turned out to be "inconvenient" to cast away the pointer's
constness before destroying the object.  That such "inconvenience"
is the whole point of const-correctness seemed lost on most of the
committee members at the time.  (Also, the vote was taken, IIRC,
very late in the afternoon.)

After the fact, more sophisticated but equally specious arguments
have arisen to justify the change, bringing in details of template
argument deduction.  All such arguments have been neatly disposed of.
(If anybody wants to try to resurrect any such arguments, I will be
happy to dispose of them again.) Still, none of the committee members
who argued for breaking const has conceded the point in public, despite
demolition of all their arguments; each has just dropped the subject.

The practical effect is that prior to the "fix", one could safely
pass or return a pointer-to-const to any function, and know that,
in the absence of a cast, nothing could be done to damage the object.
For example, one could place a sensitive resource in the object
pointed to, and know that it could not be stolen.



Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/07
Raw View
On 6 Sep 1999 20:53:57 GMT, blargg <postmast.root.admi.gov@iname.com> wrote:

>I don't buy this. It seems to be in the same class as adding a laundry
>list of features without any look at the overall picture.

Well the fact that you can delete a pointer-to-const is also a
feature, added without any look at the overall picture.  In reality,
it should not be allowed because it violates const correctness.
The destructor may call a non-const function.  And besides,
::operator delete or class::operator delete takes as its argument a
"void *", not a "void const *".

In your previous post you pointed out that because you can implicitly
delete a const object (ie, one created on the stack), you should be
able to delete a pointer to const object.  But here's the difference:
for const objects, the object is deleted at the end of the block,
when it ceases to exist; for pointer-to-const object, the object is
deleted at the user's discretion.  The rule that you can't delete
a pointer to const would add a small level of safety.

--
--------------
siemel b naran
--------------


[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/07
Raw View
In article <slrn7t8n7o.too.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:

> On 6 Sep 1999 20:53:57 GMT, blargg <postmast.root.admi.gov@iname.com> wrote:
>
> >I don't buy this. It seems to be in the same class as adding a laundry
> >list of features without any look at the overall picture.
>
> Well the fact that you can delete a pointer-to-const is also a
> feature, added without any look at the overall picture.

Yes, I see this now.

"const" isn't some theoretical feature, it's a practical concept that has
non-smooth edges.

> In reality,
> it should not be allowed because it violates const correctness.
> The destructor may call a non-const function.

Good point! It's like an implicit cast to non-const.

> And besides,
> ::operator delete or class::operator delete takes as its argument a
> "void *", not a "void const *".

Yeah, but a const operation on an object may modify its bits (mutable). An
object is more than a bad-o-bits.

[snip comment about "equivalent" code example of local const T and new const T]


[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/07
Raw View
In article <7r2m1t$n61$1@shell7.ba.best.com>, ncm@nospam.cantrip.org
(Nathan Myers) wrote:

> blargg <postmast.root.admi.gov@iname.com> wrote:
> > ncm@nospam.cantrip.org (Nathan Myers) wrote:
> >> blargg <postmast.root.admi.gov@iname.com> wrote:
> >> ><norbert@dune.gia.rwth-aachen.de> wrote:
> >> >> Is the following c++ formally o.k.?
> >> >>   void f (Foo const * p)  { delete p; }
> >> >
> >> >Lifetime is separate from const-ness. How else would you create a const
> >> >object and ever hope for it to be destroyed, if destroying/deleting a
> >> >const object were illegal?
> >>
> >> Norbert has (again) called attention to a fundamental design
> >> error in the language.  This is indeed a frequently raised topic,
> >> but is very interesting in that it never fails to elicit examples
> >> of embarrassingly specious reasoning from people who are otherwise
> >> mostly sober and clear-headed.
> >>
> >> Blargg's question above falls into that category, confusing
> >> "pointer-to-const" (which may of course point at any object)
> >> with a notional pointer-to-actually-const-object, which is not
> >> expressible in the type system.
> >
> > I am quite aware of the differences ...
> > I just don't see object lifetime as being connected to
> > const-ness (though I'm wide open to have my view changed with convincing
> > arguments).
[snip]
> In other words, if constness and object lifetime are indeed unrelated,
> then we should be discussing only the purpose of constness itself and
> whether allowing the delete-expression is consistent that purpose.

That does it :-)

There is a common dichotomy that I encounter when considering what
something should do. It is between theory and practice. This is something
that C++ has really taught me much about. So far, my arguments have been
theoretical mainly. They have dealt with concept clarity and
orthogonality.

> > My quoted statement above assumes no casting. Obviously one can cast
> > to a non-const pointer type prior to deletion.
>
> Or one can retain a pointer-to-non-const for use in deletion.
> Either is easily encapsulated by the owner of the object, and
> need not be visible to clients.

Right. new const T is really new T, then convert to const T*. new const T
should be meaningless. Just allocate with new T and use const T* to
enforce the const restriction.

> >> More interesting than the original question is why this issue
> >> drives so many people off the rails, and what it shares with
> >> other issues with the same effect.  Such issues arising in
> >> language design are very dangerous, and need to be identified
> >> early.
> >
> > Can you elaborate a bit?
>
> I appreciate the open-mindedness; it would have been welcome when
> the committee was in session.

I consider this discussion here, and when I take the view that you are not
open-minded on the issue, I don't consider the discussion worthwhile. I
suppose being open-minded means that I can't determine whether you are
closed-minded until I can see your viewpoint first. I am seeing something
new now, and have been persuaded quite well - practicality wins :-)

[snip]
> The argument that
> swayed most committee members appears to have been an argument by
> analogy; the two cases
>
>   { const T t; }            // calls T::T(), followed by T::~T().
>   { T const* tp = new T; delete tp; }
>
> were seen by many as somehow equivalent.

I came up with this "equivalence" too in considering the issue for myself,
so I am aware of its "lure".

> (At the time, "new T"
> and "new const T" were semantically identical -- the "const" was
> effectively ignored -- although this was changed with the addition
> of some rather mystical language very late in the process, well
> after the "fix".)

heh.

> The argument was that since the compiler was obliged to call the
> _destructor_ where the object goes out of scope, anybody should be
> equally free to execute a _delete-expression_ there, or anywhere.

Right. This is the theoretical argument, really. const isn't about theory,
though; it's about practical use (consider the addition of mutable, for
example).

> The practical argument for breaking const in this case was that
> it had turned out to be "inconvenient" to cast away the pointer's
> constness before destroying the object.  That such "inconvenience"
> is the whole point of const-correctness seemed lost on most of the
> committee members at the time.  (Also, the vote was taken, IIRC,
> very late in the afternoon.)

Yes. I still consider the "equivalence" example to be a little unsettling,
but const has other issues too (for example, binding a
pointer-to-non-const using "this" in a ctor, then modifying any member of
the object in a const member function - no cast!).

> After the fact, more sophisticated but equally specious arguments
> have arisen to justify the change, bringing in details of template
> argument deduction.  All such arguments have been neatly disposed of.
> (If anybody wants to try to resurrect any such arguments, I will be
> happy to dispose of them again.)

What are the arguments? (feel free to e-mail them privately if you like :-)

Hmmm, could this have to do with a template allocating an object with "new
T", where T happens to be const? (hope I didn't open the can of worms)

> Still, none of the committee members
> who argued for breaking const has conceded the point in public, despite
> demolition of all their arguments; each has just dropped the subject.
>
> The practical effect is that prior to the "fix", one could safely
> pass or return a pointer-to-const to any function, and know that,
> in the absence of a cast, nothing could be done to damage the object.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> For example, one could place a sensitive resource in the object
> pointed to, and know that it could not be stolen.

And this does it for me. Weigh this against the "inconvenience" of the
"equivalent" code example, and it tips the scales very very easily.

Const was evolved for practical use in constraining what can be done to an
object. There is no "right" way, as I see it now, for it to interact with
object lifetime. It's whatever is most practical. This argument makes it
clear which choice is more practical. It stands on the fundamental use of
const - to show that something doesn't mess with soemthing else ("just
looking").

> From a design standpoint, it should be clear to everyone that the
> purpose of "const" on an interface is to allow the interface designer
> to enforce invariants.  Prior to the "fix", an interface could be
> carefully designed to release a pointer-to-const, knowing that
> nothing (without casting) could violate its invariants.
>
> For example, one could write
>
>   T const* f() { T const* p = new T; g(p); return p; }
>
> and, without knowing anything about g() or about f()'s caller (except
> that they do not use casts), know that p was still usable and returnable.
> Now, all bets are off. Const is broken, and the best we can hope for
> is for coding standards and compilers to warn against deleting via a
> pointer-to-const.

Thanks alot. Now I'm going to be wishing my compiler warned of deletion of
a pointer-to-const :-)

> In practice, library designers, perforce, implement interfaces as if
> the change had not happened, because to wrap every pointer up in a
> class object just to enforce constness would be too messy.  The effect
> is that a common error that previously was easily detected at compile
> time is no longer easily detectable at all.
>
> That otherwise-careful committee members were swayed by such specious
> arguments in this case -- as they were, also, in the case of delete-
> expressions applied to pointers to incomplete types -- seems to me a
> cause for deep concern.

What about delete for incomplete types? Is that allowed too?!?

> Perhaps in future language design discussions,
> the "C++ Delete-Expression Fallacies" may be invoked when reasoning
> threatens to go off the rails.

heh. Thanks for putting me back on the rails.

Now, I have to ask "what else can I learn from this incident, in general,
about language reasoning?" I will be thinking about this for a while...
---
[ 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: Jeff Rife <jrife-news@nabs.net>
Date: 1999/09/01
Raw View
Steve Clamage (clamage@eng.sun.com) wrote:

> >No.  Officially, your code never calls the destructor, so it doesn't matter
> >if it is const or not.
>
> The definition of a delete-expression is that the destructor is
> invoked, followed by some version of operator delete. In what sense
> is the destructor "officially" not called?

By "officially", I meant that he never explicitly did:

cp->~C();

I know what the compiler does for the delete-expression, and said so,
although I did use the term "delete operator", instead.

> But that doesn't answer the question. An operator delete doesn't
> deal with objects; it never sees an object. It gets a pointer to
> an untyped area of raw storage (which has ceased to be an object).
> There is thus no need for an operator delete to take a parameter of
> type pointer to const.

Well, I *thought* I answered it, saying that what he did was OK, and should
work on all conforming implementations, but I guess I got the reason wrong.

> >This is one of those cases where the compiler is calling functions behind
> >the scenes, and those calls are not subject to const restrictions.
>
> No, it's because there is a special rule for this case.

And, this is where I got the reason wrong.  Sorry I missed it, as it is in
a completely different section of the standard from the delete stuff, and
sometimes finding things is tough.

--
Jeff Rife                   |
19445 Saint Johnsbury Lane  | http://www.nabs.net/Cartoons/OverTheHedge/CDChristmasList.jpg
Germantown, MD  20876-1610  |
Home: 301-916-8131          |
Work: 301-770-5800 Ext 5335 |
---
[ 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: Ron Natalie <ron@sensor.com>
Date: 1999/08/28
Raw View
Norbert Berzen wrote:

> sorry, if it's faq or if it has already been discussed.
> Is the following c++ formally o.k.?
>
> void f (void const * p)
> {
>   delete p;
> }

Const has no effect on construction or destruction.
The above is legal and the compiler is not obligated
to warn you.
---
[ 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: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1999/08/28
Raw View
On Aug 27, 1999, Norbert Berzen <norbert@dune.gia.rwth-aachen.de> wrote:

> Is the following c++ formally o.k.?
> void f (void const * p) { delete p; }

Yes and no.  You can delete const objects, yes, but deleting a void
object invokes undefined behavior, since you can't `new' a void.

> Neither egcs-1.1.2 nor tcc-4.1.2 complain

gcc 2.95+ does, AFAIR

--
Alexandre Oliva http://www.dcc.unicamp.br/~oliva IC-Unicamp, Bra[sz]il
oliva@{dcc.unicamp.br,guarana.{org,com}} aoliva@{acm.org,computer.org}
oliva@{gnu.org,kaffe.org,{egcs,sourceware}.cygnus.com,samba.org}
** I may forward mail about projects to mailing lists; please use them
---
[ 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: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/08/28
Raw View
On 27 Aug 1999 19:57:15 GMT, blargg <postmast.root.admi.gov@iname.com> wrote:
>In article <sa5aerd1ltp.fsf@dune.gia.rwth-aachen.de>, Norbert Berzen

>> Is the following c++ formally o.k.?
>>
>> void f (void const * p) { delete p; }

>How on Earth did you allocate a void?

You don't.  You allocate a real object, then cast the T* to a void*.
As C supports "delete (void*)v", C++ supports it too.

void * v=new Derived(1,2,3);
delete v;

It should be illegal because you don't call the destructor.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/08/28
Raw View
"Siemel B. Naran" wrote:
....
> As C supports "delete (void*)v", C++ supports it too.

? When did they add 'delete' to standard C? They have free(), but that's
an entirely different matter, because the destructor isn't called.

On a related matter - Section 5.3.4 p3 says:
"...if the static type of the operand is different from its dynamic
type, the static type shall be a base class of the operand's dynamic
type ..."

Is that correctly worded? At this point, the operand either was a
pointer to an object, or has been converted to one from a class object.
As such, I don't see how it's dynamic type could be different from the
static type. That sentence would make more sense to me if 'operand' were
replaced with 'object', meaning the object pointed to by the pointer.
---
[ 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: Ron Natalie <ron@sensor.com>
Date: 1999/08/30
Raw View
Siemel B. Naran wrote:

> >How on Earth did you allocate a void?
>
> You don't.  You allocate a real object, then cast the T* to a void*.
> As C supports "delete (void*)v", C++ supports it too.
>
> void * v=new Derived(1,2,3);
> delete v;
>
> It should be illegal because you don't call the destructor.
>

Excuse me.  C doesn't support "delete" anything.  C++ doesn't
support delete (void*).  The types must match the original or
be a base class of it or the behavior is undefined (it's got
nothing whatsoever to do with the destructor).



[ 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: Jeff Rife <jrife-news@nabs.net>
Date: 1999/08/30
Raw View
Norbert Berzen (norbert@dune.gia.rwth-aachen.de) wrote:

> Here are three other questions, consider:
>
>     struct C {
>       ~C() { mem = 4711; };
>       int mem;
>     };
>
>     void f (C const * cp)
>     {
>       delete cp; // C's destructor gets called.
>                  // `void operator delete (void *) throw()' gets called.
>     }
>
> Q1) Is a destructor function implicitely const qualified?

No.  Officially, your code never calls the destructor, so it doesn't matter
if it is const or not.

> Q2) The parameter of `operator delete' is not const qualified.
>     Is that o.k.?

You are not calling "operator delete" in your code.  You are using the
"delete operator".

There is a *huge* difference here, where the delete operator calls the
appropriate destructor (depending on polymorphism, etc.), and then calls
the appropriate operator delete (global or class-specific).

Then, operator delete usually just deallocates the memory.  There could, of
course, be an overridden version that does other things, and some
implementations have a "debugging" version that does some extra checking.

> Q3) Is the above `delete cp;' equivalent to the following?
>
>     cp -> ~C();
>     operator delete (cp);

Functionally, yes.

However, if you actually try the above code, a conforming compiler
should emit a diagnostic, as ~C is not declared const, and you are
calling it with a const object.

This is one of those cases where the compiler is calling functions behind
the scenes, and those calls are not subject to const restrictions.

I also believe they are not subject to access restrictions.

--
Jeff Rife                   | GCS d+(-) s: a C++++(---)$ UL++(++++)$ P+ L+$
19445 Saint Johnsbury Lane  | E--- W+++(--)$ N+ !o K? w++++(---)$ O- M--
Germantown, MD  20876-1610  | V-- PS+ PE(++) Y+ PGP t+ 5++ X+ R++(*) tv+
Home: 301-916-8131          | b+++ DI++++ D++ G+(++++) e+(*) h++(*) r* y?
Work: 301-770-5800 Ext 5335 |


[ 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: David R Tribble <david@tribble.com>
Date: 1999/08/30
Raw View
Norbert Berzen wrote:
>
> Sorry, if it's faq or if it has already been discussed.
> Is the following c++ formally o.k.?
>
>    void f (void const * p)
>    {
>      delete p;
>    }
>
> Neither egcs-1.1.2 nor tcc-4.1.2 complain and I do not
> get any clue reading the c++-draft. Do I miss something?

Many pre-ISO compilers warned about deleting a const object.
ISO C++ allows it, and the compiler is not obliged to issue a
warning.

This has been the source of much discussion in the past (circa
May 1999, I think).  Some feel that it's a convenience to allow
deleting a const object without requiring an explicit cast to
remove the constness, while others feel that this opens up a hole
in the type safety of the language by allowing a function that
does not own an object to delete it.  The debate was never settled.

BTW, your example should have used 'const Type * p' instead of a
void pointer.

-- David R. Tribble, david@tribble.com --


[ 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: Ron Natalie <ron@sensor.com>
Date: 1999/08/31
Raw View
Norbert Berzen wrote:

Perhaps I'm missing some gedanken experiment you are trying
to perform here, but:

>
> Q1) Is a destructor function implicitely const qualified?

Destructor's can't be declared const.  Nor is it necessary
to do so, they may be invoked on const objects.  Constness
doesn't apply inside the destructor.

>
> Q2) The parameter of `operator delete' is not const qualified.
>     Is that o.k.?

Yes.

>
> Q3) Is the above `delete cp;' equivalent to the following?
>
>     cp -> ~C();
>     operator delete (cp);
>

No, because the CV qualification on cp doesn't apply to
the call of operator delete here.
---
[ 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: clamage@eng.sun.com (Steve Clamage)
Date: 1999/08/31
Raw View
Jeff Rife <jrife-news@nabs.net> writes:

>Norbert Berzen (norbert@dune.gia.rwth-aachen.de) wrote:

>> Here are three other questions, consider:
>>
>>     struct C {
>>       ~C() { mem = 4711; };
>>       int mem;
>>     };
>>
>>     void f (C const * cp)
>>     {
>>       delete cp; // C's destructor gets called.
>>                  // `void operator delete (void *) throw()' gets called.
>>     }
>>
>> Q1) Is a destructor function implicitely const qualified?

>No.  Officially, your code never calls the destructor, so it doesn't matter
>if it is const or not.

The definition of a delete-expression is that the destructor is
invoked, followed by some version of operator delete. In what sense
is the destructor "officially" not called?


>> Q2) The parameter of `operator delete' is not const qualified.
>>     Is that o.k.?

>You are not calling "operator delete" in your code.  You are using the
>"delete operator".

>There is a *huge* difference here, where the delete operator calls the
>appropriate destructor (depending on polymorphism, etc.), and then calls
>the appropriate operator delete (global or class-specific).

But that doesn't answer the question. An operator delete doesn't
deal with objects; it never sees an object. It gets a pointer to
an untyped area of raw storage (which has ceased to be an object).
There is thus no need for an operator delete to take a parameter of
type pointer to const.


>> Q3) Is the above `delete cp;' equivalent to the following?
>>
>>     cp -> ~C();
>>     operator delete (cp);

>Functionally, yes.

Well, it depends. The delete-expression always invokes the
destructor, then calls some version of operator delete.  If
class C has a member operator delete, the delete-expression
calls it, but the replacement code (as shown) won't.

>However, if you actually try the above code, a conforming compiler
>should emit a diagnostic, as ~C is not declared const, and you are
>calling it with a const object.

No diagnostic needs to be emitted, because you are explicitly
allowed to delete an object via a pointer to const. You are not
allowed to declare a destructor to be const (or volatile). The
(one and only) destructor for a class can be invoked on any
object, whether or not it is const.

>This is one of those cases where the compiler is calling functions behind
>the scenes, and those calls are not subject to const restrictions.

No, it's because there is a special rule for this case.

And even when a function is implicitly called, all the access
rules apply. For example, this code should not compile:

class C {
    ~C(); // private
};
void f()
{
    C c; // error, C::~C() not accessible
}

--
Steve Clamage, stephen.clamage@sun.com


[ 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: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/08/31
Raw View
Norbert Berzen wrote:
>
> Thanks for your answeres.
> Here are three other questions, consider:
>
>     struct C {
>       ~C() { mem = 4711; };
>       int mem;
>     };
>
>     void f (C const * cp)
>     {
>       delete cp; // C's destructor gets called.
>                  // `void operator delete (void *) throw()' gets called.
>     }
>
> Q1) Is a destructor function implicitely const qualified?

yes, although you can't write const on a dtor:

struct T {
    ~T () const; // error
};

> Q3) Is the above `delete cp;' equivalent to the following?
>
>     cp -> ~C();
>     operator delete (cp);

Assuming no exceptions, with no member operator delete, yes

> I know the code above is complete nonsense.

To me it's very sensible and useful code.

--

Valentin Bonnard


[ 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: wmm@fastdial.net
Date: 1999/08/30
Raw View
In article <37C7E963.BD34BFE7@wizard.net>,
  "James Kuyper Jr." <kuyper@wizard.net> wrote:
> On a related matter - Section 5.3.4 p3 says:

Actually, it's 5.3.5p3, in case anyone was confused.

> "...if the static type of the operand is different from its dynamic
> type, the static type shall be a base class of the operand's dynamic
> type ..."
>
> Is that correctly worded? At this point, the operand either was a
> pointer to an object, or has been converted to one from a class
object.
> As such, I don't see how it's dynamic type could be different from the
> static type. That sentence would make more sense to me if 'operand'
were
> replaced with 'object', meaning the object pointed to by the pointer.

You are, of course, correct -- the last sentence of the paragraph,
which is obviously parallel to the one you cited, says "dynamic type
of the object to be deleted," which is what was intended here, too.

The Standard isn't as careful as it might be about applying the term
"dynamic type" to a pointer; cf 5.2.2p1, where the phrase "dynamic
type of an object expression" is defined as "the type of the object
pointed or referred to by the current value of the object expression,"
even though the object expression can be a pointer.

I don't think this is a particularly serious problem, though.  Since
pointers themselves cannot have different static and dynamic types,
it's reasonably clear that the phrase "dynamic type of a pointer" is
just a shorthand for "dynamic type of the object to which a pointer
points," although technically incorrect.

--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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: Norbert Berzen <norbert@dune.gia.rwth-aachen.de>
Date: 1999/08/30
Raw View

Thanks for your answeres.
Here are three other questions, consider:

    struct C {
      ~C() { mem = 4711; };
      int mem;
    };

    void f (C const * cp)
    {
      delete cp; // C's destructor gets called.
                 // `void operator delete (void *) throw()' gets called.
    }

Q1) Is a destructor function implicitely const qualified?

Q2) The parameter of `operator delete' is not const qualified.
    Is that o.k.?

Q3) Is the above `delete cp;' equivalent to the following?

    cp -> ~C();
    operator delete (cp);


I know the code above is complete nonsense. I only think
there may be formal inconsistencies?

--
Norbert Berzen, Geodaetisches Institut der RWTH Aachen,
Templergraben 55, D-52062 Aachen
e-mail: norbert@dune.gia.rwth-aachen.de


[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/08/27
Raw View
In article <sa5aerd1ltp.fsf@dune.gia.rwth-aachen.de>, Norbert Berzen
<norbert@dune.gia.rwth-aachen.de> wrote:

> Hi,
>
> sorry, if it's faq or if it has already been discussed.
> Is the following c++ formally o.k.?
>
> void f (void const * p)
> {
>   delete p;
> }

How on Earth did you allocate a void?

    void* p = new void; // sorry

It's undefined, first of all, regardless of const.

If it were some other type, like char const*, then it would be fine.
Lifetime is separate from const-ness. How else would you create a const
object and ever hope for it to be destroyed, if destroying/deleting a
const object were illegal?


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