Topic: Delete through const pointer


Author: "Dave Abrahams" <abrahams@mediaone.net>
Date: 1999/12/09
Raw View
In article <374461C0.4F59A799@technologist.com> , David R Tribble
<dtribble@technologist.com>  wrote:

> But of course, I'm only half-serious about this.

That's good, because a const_cast will let you remove any of the consts in
the type (const char *const *const), and your syntax doesn't have any way to
support that.

> What bothers me
> is the amount of verbiage needed to convert an old-style cast like:
>
>     const Base *  bp;
>     Der *         dp;   // Der inherits Base
>
>     dp = (Der *) bp;
>
> into:
>     dp = static_cast<Der *>(const_cast<Base *>(bp));
> or:
>     dp = const_cast<Der *>(static_cast<const Der *>(bp));
>
> Yes, the intent is clearer, but wading through all that code can be,
> in the balance, equally as annoying.

That's because you're making the wrong modernization. I suggest you either:
1. Not touch the code because it works
2. Change the code to the new, ugly syntax and hope it alerts readers that
it's probably a bug
3. or, find a clean way to avoid the cast through redesign. There is
probably a way!
---
[ 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: Herb Sutter <HSutter@peerdirect.com>
Date: 1999/05/19
Raw View
On 18 May 99 22:51:01 GMT, David R Tribble <dtribble@technologist.com>
wrote:
>Or perhaps a "default" const_cast would simply return a type that
>has the opposite constness of its operand.  In other words:
>
>    Object *        p;
>    const Object *  cp;
>
>    const_cast<>(p)   // same as const_cast<const Object *>(p)
>    const_cast<>(cp)  // same as const_cast<Object *>(cp)

Except that const is only one of the two cv-qualifiers. If it worked to
"flip" the cv-qualifiedness, the effect would instead be:

    const_cast<>(p)   // const_cast<const volatile Object *>(p)
    const_cast<>(cp)  // const_cast<volatile Object *>(cp)

Herb


---
Herb Sutter (mailto:hsutter@peerdirect.com)

PeerDirect Inc.                     www.peerdirect.com
2695 North Sheridan Way, Suite 150  Tel: 416-805-9088
Mississauga Ontario Canada L5K 2N6  Fax: 905-822-3824



[ 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: AllanW <allan_w@my-dejanews.com>
Date: 1999/05/19
Raw View
In article <3741EDFB.7D68C368@technologist.com>,
  David R Tribble <dtribble@technologist.com> wrote:
> [Discussing delete of pointer-to-const operands...]
> Or perhaps a "default" const_cast would simply return a type that
> has the opposite constness of its operand.  In other words:
>
>     Object *        p;
>     const Object *  cp;
>
>     const_cast<>(p)   // same as const_cast<const Object *>(p)
>     const_cast<>(cp)  // same as const_cast<Object *>(cp)

Complete the thought. What happens to more complex cases?

      // Does this
      Object const * * cpp;
      const_cast<>(cpp)
      // cast to    Object**    or to      Object*const*    ?

      // Does this
      Object * const * pcp;
      const_cast<>(pcp)
      // cast to    Object**    or to      Object const**   ?

      // Does this
      Object const * const * cpcp;
      const_cast<>(cpcp)
      // Remove both consts? If only one, which one?

      // What happens to
      Object * * const * * const * x;
      const_cast<>(x)

> In fact, is it ever the case that const_cast is given a different
> type (other than cv-specifiers) to cast its operand to?
That wouldn't be a valid use of const_cast

> Is it ever really necessary to specify the type?
Need to be able to specify all the places that const belongs.
Removing the type from the definition would require some alternate
scheme to accomplish this.

--
Allan_W@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in newsgroups only, sorry.


--== 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: David R Tribble <dtribble@technologist.com>
Date: 1999/05/20
Raw View
Herb Sutter wrote:
>
> David R Tribble <dtribble@technologist.com> wrote:
>> Or perhaps a "default" const_cast would simply return a type that
>> has the opposite constness of its operand.  In other words:
>>
>>    Object *        p;
>>    const Object *  cp;
>>
>>    const_cast<>(p)   // same as const_cast<const Object *>(p)
>>    const_cast<>(cp)  // same as const_cast<Object *>(cp)
>
> Except that const is only one of the two cv-qualifiers. If it worked
> to "flip" the cv-qualifiedness, the effect would instead be:
>
>     const_cast<>(p)   // const_cast<const volatile Object *>(p)
>     const_cast<>(cp)  // const_cast<volatile Object *>(cp)

Ah, I forgot that.  Of course, in that case a possible abbreviated
cast syntax could be:

    const_cast<const>(p)    // == const_cast<const Object *>(p)
    const_cast<volatile>(p) // == const_cast<volatile Object *>(p)
    const_cast<>(cp)        // == const_cast<Object *>(p)

But of course, I'm only half-serious about this.  What bothers me
is the amount of verbiage needed to convert an old-style cast like:

    const Base *  bp;
    Der *         dp;   // Der inherits Base

    dp = (Der *) bp;

into:
    dp = static_cast<Der *>(const_cast<Base *>(bp));
or:
    dp = const_cast<Der *>(static_cast<const Der *>(bp));

Yes, the intent is clearer, but wading through all that code can be,
in the balance, equally as annoying.

-- David R. Tribble, dtribble@technologist.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 <dtribble@technologist.com>
Date: 1999/05/18
Raw View
[Discussing delete of pointer-to-const operands...]

David R Tribble <dtribble@technologist.com> wrote:
>> As to Andy's template example, it is definitely a problem.
>> Unless we allow an exception in the typing system.  Namely, that
>> we make it illegal to delete a pointer-to-const unless the pointer's
>> type is derived from a template type parameter.  So Dave's example
>> would result in a compiler warning (or error), and Andy's example
>> would compile just fine.

Andras Erdei wrote:
> Another solution would be to allow
>
>   const_cast<>( tp )
>
> A "default" const_cast should remove the
> leftmost/rightmost/all 'const' from a type.

Or perhaps a "default" const_cast would simply return a type that
has the opposite constness of its operand.  In other words:

    Object *        p;
    const Object *  cp;

    const_cast<>(p)   // same as const_cast<const Object *>(p)
    const_cast<>(cp)  // same as const_cast<Object *>(cp)

In fact, is it ever the case that const_cast is given a different
type (other than cv-specifiers) to cast its operand to?  Is it
ever really necessary to specify the type?

-- David R. Tribble, dtribble@technologist.com --
   A little government and a little luck are necessary in life,
   but only a fool trusts either of 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: ccg@freemail.c3.hu (Andras Erdei)
Date: 1999/05/18
Raw View
David R Tribble <dtribble@technologist.com> wrote:

>Dave Harris <brangdon@cix.co.uk> wrote:
>>> The main motivation for allowing it seems to be cases like:
>>
>>>     void proc() {
>>>         const Object *pObject = new Object;
>>>         //...
>>>         delete pObject;
>>>     }
>>
>>> where we are imitating auto scope.
>
>Andrew Koenig wrote:
>> That argument is not particularly important in that particular form.
>> The form that is important is
>>
>>         template<class T> void proc(args) {
>>                 T *tp = new T;
>>                 // ...
>>                 delete tp;
>>         }
>>
>> Now, you don't know whether T is a const type.  If you could not say
>> "delete tp;" directly, there is no cast you could write that would
>> allow it.
>snip<
>As to Andy's template example, it is definitely a problem.
>Unless we allow an exception in the typing system.  Namely, that
>we make it illegal to delete a pointer-to-const unless the pointer's
>type is derived from a template type parameter.  So Dave's example
>would result in a compiler warning (or error), and Andy's example
>would compile just fine.

Another solution would be to allow

  const_cast<>( tp )

A "default" const_cast should remove the
leftmost/rightmost/all 'const' from a type.




[ 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: kramsay@aol.com (KRamsay)
Date: 1999/04/19
Raw View
ncm@nospam.cantrip.org (Nathan Myers) writes:
|J.Barfurth<techview@bfk-net.de> wrote:
|>I still maintain, that the compiler should not disallow me to handle
|>lifetime issues separately from constness issues.
|
|No one has argued that.  You can handle lifetime issues any way
|you like, ARM rule or no.  The argument is simply that not to
|require use of const_cast<> when you violate constness was a
|design error.

Calling it "violating constness" is completely question begging, when
the whole object is to decide what to make "const" mean.

If the rule were changed back to disallow deletion through a pointer-
to-const, I suspect I might continue using much the same style as I
presently do, but with one of these little workarounds that have been
advertised here. I consider doing this NOT to be a negligible penalty
to pay, though; it's a bad thing to get used to writing code which
says either "I'm violating an important protection here, naughty me"
or alternatively "I don't like this rule they put into the standard".
I have written a const_cast-- to get around a library routine which
has not yet been written to take a const argument where appropriate--
but ideally I think the goal should be to avoid them completely if
at all practical.

So the only way I can see it making sense to go back to the old rule
would be if it were actually a good idea not to treat it as something
to be circumvented. I would want to know of a superior style which
involved never deleting a const object through a pointer, with no
special ifs ands or buts. (Wouldn't this also extend to objects which
though not const themselves have const members, by the way?)

Most of the time, my objects are constructed and destructed in parallel
ways. Most of them would remain equally unproblematic. Objects
created on the heap wouldn't. It seems that in cases where I would now
write {const Foo *p=new Foo; ... ; delete p;}, the "very const correct"
style would lead me just to drop the constness. Yes, there are these
workarounds, but as I said I consider it a significant problem if
there isn't a reasonable coding style which doesn't require using
const_cast. What appropriate alternative am I not thinking of here?
The likely outcome seems to be that I would drop the const, and no
longer get any warning if I modify (or destroy) *p anywhere in the
middle.

It's been said that the old rule doesn't discriminate against objects
on the free store. That reminds me of the famous remark that the law
against sleeping under bridges applies equally to the rich and the
poor. We have agreed that the obvious, simplest possible meaning of
"const" (does not change ever) is much too strong, so we allow some
destruction of const objects but only special kinds. Effectively the
non-free store objects have better access to ways of being const, and
yet being destroyed in these priviledged ways (such as being
destructed at a "}") than free store objects do.

People have mentioned several times the case of a pointer being passed
to a function (which possibly deletes on it). I haven't noticed anyone
mention the reverse, passing ownership up from a function to its
calling function. I think I am at least as likely to do that. I might
have some function whose job it is to create a tree-like structure on
the free store and pass back a pointer to its base. I might want to be
discouraged from making changes in it (or in some part of it). What
would I do then? It seems that (still trying to be const correct) I
would just not use const. The value of ensuring that the object
persists is rather less; here the (dual) requirement we want satisfied
is that the object has already been created. The stronger sense of
const doesn't seem to help with that, and I wouldn't get to use it
anyway.

The case where the value of the stronger const seems greatest, is in
cases where I have no intention of transferring ownership, the object
isn't on the free store, and I want it not to change within the block
where it's defined. Then, there would be this added protection which
has been argued; I admit it. I might inadvertently try to delete the
object, and I would be warned against it. [I don't actually remember
any instance where (under the new rule) in such a situation I've
mistakenly and prematurely destroyed the object. Memory leaks, alas
yes, forgetting to delete something and feeling stupid about it, I do
that. My bet is that if I were to prematurely delete something, it
would most often be in cases where I had fully intended to delete it
through a pointer (rather than let it be implicitly destroyed) but got
the design confused so that I did it twice.]

One of the reasons why I'm unconvinced of the benefits of that
protection being big, is that as things stand, the likelihood of my
making this mistake doesn't seem to be well correlated with constness.
If I were to write void f(Foo *p){...; delete p; ...} my impression is
that it would be as likely to be a premature destruction (that I had
otherwise intended to occur elsewhere), as if I had written
void f(const Foo *p){...; delete p; ...}.

One might prevent some mistakes of either kind, by having the compiler
require additional hand-washing moves when I write a delete, regardless
of the circumstances. If one made a compiler which asked "are you
really sure you mean to do that?", whenever I deleted anything, it
might help avoid errors, but not very well since one would become
somewhat jaded to this warning after awhile. I suggest the principle
that it only give warnings in cases which are distinctly more likely
to be other than what one really intended to do. Under the current
rule, I don't see that this is so. Show me a "delete" applied to a
pointer-to-const, and ask me if I meant to delete it there, and my
reaction is (under the present rule) likely to be about the same, as
if you asked the same thing about a pointer-to-nonconst.

I think you are completely mistaken in your assessment of why some
people are regarding lifetime and const as independent. Presumedly it
comes down to different ways of thinking. We can make a table of cases,

                     Non-const              Const

Intent to pass       void f(Foo *p)         void f(const Foo *p)
ownership            {...; delete p;...}    {...; delete p; ...}

Intent not to pass   No deletion            No deletion
ownership

There are many other rows we could devise. The analogies along rows
and columns are not just some rhetorical stratagem; the relevant
characteristics of the situations seem to follow them. I might make
a mistake by thinking I was in the upper left corner, when I was in
the lower left corner; I might make a mistake by thinking I was in the
upper right corner when I was in the lower right corner. These are not
"exactly the same" mistake, but they seem to all intents and purposes
to be the same. Likewise (!) the mistake of thinking that one is in
the upper left corner when one is in the upper right corner and the
mistake of thinking that one is in the lower left corner when one is
in the lower right corner seem practically speaking to be the same.
One seems to have the same mental slips involved in doing them,
essentially the same frequency of occurrence, etc.

If one were already in a habit of thinking the upper right corner to
be damnable nonsense, then these parallels would fail, of course.
If the old rule were reinstated (and I tried to keep to the spirit of
it and remain const-correct) I suppose there would *come to be* a
correlation between constness and deletion being an error. Suppose I
*stopped using* const for cases where I wanted to pass ownership
around, or for objects on the free store. The remaining occurrences of
"const" in my code would (then) be just the cases where the (rare, I
think) inadvertent delete's *would* be mistakes. Despite what you seem
to think, I think proponents of the new rule do understand that there
is a certain advantage to this. But I don't think it is all that large,
and I don't see that it outweighs the likelihood of people ceasing to
use const in these other perfectly legitimate cases, where they merely
want to handle lifetimes in other than a plain vanilla way, construct
and destruct on the heap, or the harm of the crummy situation where
they get used to using const_casts to circumvent it.

I think "remains in the same state from construction to destruction"
is as clear and comprehensible a definition as anything besides "does
not change ever", including "does not change except for construction
and the compiler's destroying it". It appeals to my sense of elegance,
and I haven't heard of any actual instances of mistakes which would
have been prevented by changing it. I think it's OK. I'm prepared to be
convinced otherwise, but only by something I've overlooked so far.

Keith Ramsay
---
[ 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: Joerg Barfurth <jbarfurth@vossnet.de>
Date: 1999/04/19
Raw View
Fergus Henderson wrote:
> =

> Biju Thomas <b_thomas@ibm.net> writes:
> =

> >Doesn't this mean that there can be const (and volatile) objects on th=
e
> >heap?
> =

> Yes, it does.  However, unfortunately 3.8 "Object Lifetime [basic.life]=
"
> paragraph 9
> =

>  |      -9- Creating a new object at the storage location that a const =
object
>  |      with static or automatic storage duration occupies or, at the s=
torage
>  |      location that such a const object used to occupy before its lif=
etime
>  |      ended results in undefined behavior.
> =

> restricts itself to objects with static or automatic storage duration.
> This makes it difficult for an implementation to actually write-protect=

> objects on the heap.
> =

> If this paragraph included objects with dynamic storage duration,
> then the implementation would have more freedom to write-protect things=
=2E
> For example, if the compiler sees
> =

>         const Object *p;
> =

>         int main() {
>                 p =3D new const Object("blah");
>                 ...
>         }
> =

> and the implementation detects that the program has not overriden
> the global operator new or delete, then the compiler could inline
> the constructor for `Object', execute it at compile time, and place
> the resulting value in ROM.  (Of course for this to work the global
> operator delete should handle deallocations of such values appropriatel=
y,
> e.g. by ignoring any attempts to deallocate memory in ROM.)
> =

> As a more useful example, debugging implementations (like Purify,
> ObjectCenter, etc.) could dynamically write-protect memory whenever
> the constructor for a const object finished executed, and dynamically
> disable that write-protection whenever the destructor started executing=
=2E
> This could apply to all memory areas -- static memory, stack and heap.
> =

> However, with 3.8 paragraph 9 restricted as it is, it is pretty hard
> for an implementation to write-protect memory on the heap.  I think
> this is what Nathan meant when he said "There is no such thing as a
> const object on the heap".  A user is free to write code such as
> =

>         new (p) const Object("something else");
> =

> or even to reuse the storage for some entirely different type
> =

>         new (p) int(42);
> =

> and in both cases the user does not need to delete the old const object=

> first, and does not need to call its destructor first either.
> =

> I don't know what the rationale for including the words
> "with static or automatic storage duration" in 3.9 paragraph 9 was.
> Perhaps someone could explain it to me.

To begin with I cannot explain the rationale of the committee. I see some=

reason for this restriction though.

Firstly it is efficiency. =

As was already stated by others, the main difference between static/autom=
atic
and dynamic storage duration is, that storage duration [basic.stc] and
moreover lifetime [basic.lifetime] of static/automatic objects are fully =
known
at compile time. If the compiler wants to write-protect storage for
static/automatic const objects (and remove that protection for destructio=
n),
it can do so at well known times. =

For nonmodifiable lvalues the compiler generally has no information, whet=
her
the object referred to is actually const or not. Normally the lifetime of=
 a
const object of dynamic storage duration would be ended by a delete-expre=
ssion
involving a pointer to such an object. So here the compiler would have to=

check for write-protected memory (or tentatively remove write-protection)=
 on
each such expression. This could in many cases greatly reduce the efficie=
ncy
of such a delete-expression. (As I mentioned elsewhere there also are val=
id
uses of delete-through-const-pointer for non-const objects - e.g. smart
pointers). Most opponents of deleting through const pointers on this thre=
ad
suggest that this could be replaced by a delete-expression involving a
const_cast'ed version of the original pointer. For our problem this would=

extend the necessity of checking write-protection to every delete-express=
ion.

Moreover [3.8 p 9] is an exception to a more basic rule (constness ends w=
ith
lifetime - lifetime ends with reuse, so constness ends with reuse). It is=

possible for auto/static objects, as it's effect is well localized there.=
 For
objects of dynamic storage duration, it would globally affect legal
constructs. =


Third, reuse of storage of auto/static objects is already strongly restri=
cted,
as it has to deal with implicit detructor calls (see [3.8 p 8]).
OTOH for const objects of dynamic storage duration there are ways to sepa=
rate
their (actual) storage duration from their lifetime. Example: (T of class=
 type
with non-trivial d'tor)
 void * v =3D ::operator new(sizeof(T)); // begin storage duration =

 //... =

 T const* t =3D ::new(v) const T;   // begin lifetime, begin constness
 //...
 t->~T();        // end constness, end lifetime - legal according to [12.=
4 p 2]
 //... reuse memory without problems
 ::operator delete(v);     // end storage duration
 // no implicit destructor calls to be afraid of
 =

So it seems that 'storage constness' can be separated from 'logical/objec=
t
constness' much more easily for objects of dynamic storage duration.

-- J=F6rg
---
[ 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: "AllanW {formerly AllanW@my-dejanews.com}" <allan_w@my-dejanews.com>
Date: 1999/04/16
Raw View
In article <QQgkbu15385.199904081739@relay4.UU.NET>,
  "Andrei Alexandrescu" <andreia@netzip.com> wrote:
> John D. Hickin <hickin@hydro.cam.org> wrote in message
> news:370B52D4.4FF7@pop.hip.cam.org...
> > I argue that destruction is logically const because no observation that
> > you may undertake afterwards can detect a change of state.
>
> Crashing the program is quite observable to me.

But the standard doesn't guarantee that your program will crash if you
access a deleted object (or if you double-delete it). All it says is
that your program is non-compliant.

----
Allan_W@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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: "Niklas Borson" <a-niklab@microsoft.com>
Date: 1999/04/18
Raw View
Nathan Myers <ncm@nospam.cantrip.org> wrote in message
news:7f1m7m$sbb$1@shell7.ba.best.com...
> <sirwillard@my-dejanews.com> wrote:
> > ark@research.att.com (Andrew Koenig) wrote:
> >> But we don't have dynamic.  So the question is how this attribute
should
> >> be expressed within the C++ type system.  There seem to be two
alternatives:
> >> 1. Link it to const.
> >> 2. Don't express it in the type system.
> >
> >That said, I think we're back to the original point here.
>
> Exactly: it begs the question, and reveals nothing.  The only reason
> anybody tried to separate lifetime from constness was the easy syntactic
> distinction.  Experience shows that the semantic distinction is not
> nearly so neat, if indeed it is meaningful at all.
> [...]

I agree with what I take to be Nathan's goal, namely,
it should be possible to state as part of a function's
contract that it does not delete an object.

But I still think lifetime and constness are separate.
Consider this:

  void square(T in, T& out)
  {
      out = in * in; // I want to allow this,
      delete &out;   // but not this
  }

Here, I want to grant "change" permission but deny "delete"
permission. Using one type qualifier (const) for both
permissions would not be fine-grained enough.

Perhaps the real problem here is not const, but new and delete.
There are no guarantees of object lifetime as long as people
are allowed to call new and delete directly (rather than using
smart pointers of some kind), and making delete private seems
to have no effect.
---
[ 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: Matt Austern <austern@sgi.com>
Date: 1999/04/15
Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:

> On 08 Apr 99 13:06:40 GMT, Matt Austern <austern@sgi.com> wrote:
>
> >What Andy's example does mean, though, is that you can't forbid
> >    "delete x"
> >by making general rule about about destructors and const objects.
> >Forbidding it would require a special-case rule dealing with the
> >specific syntactic construct of a delete-expression.  We would then
> >have to worry, on a case-by-case basis, about other syntactic
> >constructs that can result in a destructor getting invoked.
>
> No, my rule is simple.  In the statement "delete x", 'x' must be
> a pointer to non-const.  End of story.

Well, that's what I mean by a special-case rule: first we've got a
rule saying that it's OK for the member function X::~X() to be invoked
even when the 'this' pointer is of type const X*, and then we would
have a new special-case rule saying that it's not OK when the
destructor happens to be invoked via the specific expression
'delete x'.

As I said, that leads to the interesting question of how we would
handle other syntactic forms that result in X::~X() getting invoked.
For example, how about x->X::~X()?
---
[ 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/04/16
Raw View
Matt Austern <austern@sgi.com> wrote:
>sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
>> Matt Austern <austern@sgi.com> wrote:
>>
>> >What Andy's example does mean, though, is that you can't forbid
>> >    "delete x"
>> >by making general rule about about destructors and const objects.
>> >Forbidding it would require a special-case rule dealing with the
>> >specific syntactic construct of a delete-expression.  We would then
>> >have to worry, on a case-by-case basis, about other syntactic
>> >constructs that can result in a destructor getting invoked.
>>
>> No, my rule is simple.  In the statement "delete x", 'x' must be
>> a pointer to non-const.  End of story.
>
>Well, that's what I mean by a special-case rule: first we've got a
>rule saying that it's OK for the member function X::~X() to be invoked
>even when the 'this' pointer is of type const X*, and then we would
>have a new special-case rule saying that it's not OK when the
>destructor happens to be invoked via the specific expression
>'delete x'.

This argument, again, begs the question.  The claim is that being
allowed to destroy an object to which you have only const access
breaks constness itself.  That this was allowed using the "p->~T()"
syntax was already a bug (though less harmful) in the ARM.  The
committee added a second and worse bug by extending it to operator
delete.

Of course, it is silly to talk about "special case" rules applying
to the delete expression: the delete expression is itself unique,
as must be any rule defining it.

>As I said, that leads to the interesting question of how we would
>handle other syntactic forms that result in X::~X() getting invoked.
>For example, how about x->X::~X()?

The sensible rule is very, very simple to state: the destructor is
non-const.  Compiler-generated destructor calls on const objects are
"as if" const_cast<T*>(p)->~T(), after any (supposed) write-enabling
of the affected storage.

That the committee did not fix permissions on explicit calls to ~T()
is understandable; that it swallowed such specious arguments for
extending the error is comprehensible only by considering the
committee members' human fallibilities.

--
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/04/16
Raw View
David R Tribble <dtribble@technologist.com> wrote:
>Nathan Myers wrote:
>> The much-simpler solution is for the factory itself to provide
>> another method to dispose of the instance it constructed.  There
>> might be other reasons to use a wrapper class, however.
>
>That was my first thought, too: if a class provides a factory
>creation function Foo::create(), it ought to also provide a
>disposal function Foo::destroy().  ...
>If you declare it as taking a 'const Foo *', it has to cast away
>the const in order to call the delete operator (assuming this is
>how C++ /should/ do it).

Exactly: fixing the language-design problem wouldn't prevent you
from implementing the design you wanted to write; it would only
mean you must use a const_cast<> to do it.

Note that the design is still less hazardous than what was originally
proposed; it's a lot harder to call aFactory->dispose(p) accidentally
when you don't have a copy of aFactory on hand, vs. using the global
"delete" improperly.

(Incidentally, allowing "delete" on incomplete pointer types must also
rank among the committee's worse gaffes.)

--
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/04/16
Raw View
J.Barfurth<techview@bfk-net.de> wrote:
>
>I still maintain, that the compiler should not disallow me to handle
>lifetime issues separately from constness issues.

No one has argued that.  You can handle lifetime issues any way
you like, ARM rule or no.  The argument is simply that not to
require use of const_cast<> when you violate constness was a
design error.  Nothing J. (or indeed, anybody else) has written
so far supports a counterargument.

>Then later when I'm really through using it, I might not have the proper
>'factory' available.

OK, so make the dispose() function global.
You can, and always could, make any design as unsafe as you like.

What is at issue is whether you are allowed to make a rigorously
safe design.  Under the status quo, you _cannot_.  This is what
made the decision such a grave design error.

--
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: sirwillard@my-dejanews.com
Date: 1999/04/13
Raw View
In article <F9vqy7.3on@research.att.com>,
  ark@research.att.com (Andrew Koenig) wrote:

[snipped lots of discussion about the seperation of lifetime from
other "attributes" of the object, and the new keyword dynamic to designate a
type that can have it's lifetime modified by the use of delete]

> But we don't have dynamic.  So the question is how this attribute should
> be expressed within the C++ type system.  There seem to be two alternatives:
>
>  1. Link it to const.
>
>  2. Don't express it in the type system.
>
> Both these alternatives have advantages and disadvantages, and opinion has
> always been divided about which one is better.  I personally favor (2),
> but many people whom I personally respect favor (1).  Realizing that there
> is really another attribute here has convinced me that this debate cannot
> be definitively settled within the language as it exists today.

If one were to seperate the issue in this way (meaning to add new keywords to
the language) then I'd agree, though I think you've chosen the wrong path.  It
seems more logical to have a keyword that indicates an objects lifetime CAN'T
be modified, with the default being that it can.  Maybe "dynamic" should
be "persistent" and follow the inverse semantics.

That said, I think we're back to the original point here.  Even if one likes
option 1) above (basically that you can't delete a const object), I fail to
see how such a ruling can be considered "intuitive".  It means that you
follow different rules for dynamic objects than you do for local objects
(meaning that the destructor can be called on const objects for local types).
 This is hardly intuitive.  Therefore, option 2) above seems to be the
"logical" choice, and the one adopted by the standard, like it or not.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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/04/13
Raw View
Andrei Alexandrescu<andreia@netzip.com> wrote:
>I agree that the existence of a genuinely const heap seriously shatters the
>arguments of the anti-standard participants to this discussion. Someone
>quoted from the standard that "calling the new operator on a cv-qualified
>type returns a pointer to a cv-qualified type", which at least leaves room
>for implementing a const heap.

Not quite.  There is no argument to operator new() to tell it
that the object is to be const, so should be placed in a write-
protected page.  A user- or vendor-defined operator new() could
have such an argument, but then regular delete could not be
used on the object.

>On the other hand, delete-ing const object has several disdvantages, which
>leads to quite an unpleasant state of affairs.

The reason for placing the objects in read-only storage would be to
prevent them being damaged accidentally.  Being deleted by code which
only happened to get a copy of the pointer would be a good example
of such damage.  Thus, to be useful one would need to be able to
specify (e.g. via a ticket) that one had the right to destroy the
object.

>So from now on, whenever someone brings up an argument against the standard
>in this issue, a solution to the const heap issue should be brought up as
>well.

Because of the problems, a const heap is purely theoretical
and can can only confuse matters.

>IMHO, I would like to see a solution that would strengthen the consistency
>of const. As we all know, const is an awesome design tool in C++. Having
>better const-guarantees leads ultimately to better C++ programs.

The language is _not_ going to be fixed.
However, better warnings would be almost as good.  There are three:

  warning: destructor call on pointer-to-const
  warning: destructor call on reference-to-const
  warning: delete of pointer-to-const

Of course const_cast<> could be used to quiet any instance of
such a warning.

--
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/04/13
Raw View
andreia@netzip.com (Andrei Alexandrescu) wrote:
> There is a slight mistake, I think, that I'd like to point out.
> [...]
> It's easy to conceive a const heap allocator that unprotects memory
> prior to do a construction/destruction and protects it again when
> that process ends.

I meant that it does not make sense to destroy a const object. If one must
be destroyed, the constness must be removed first. For truly const objects
on a hardware protected, const heap, const_cast<> cannot do that. Some new
mechanism is needed. Hence my 4th suggestion.

If the standards committee wanted to introduce const heaps, that would
have been a reasonable way to go. Although it doesn't sound as though they
thought of it in those terms, which makes this line of argument moot.


> So from now on, whenever someone brings up an argument against the
> standard in this issue, a solution to the const heap issue should
> be brought up as well.

I'm such a someone and I've given you 4 solutions :-)

But seriously, I think you're misplacing the burden of proof. As I
understand it, const heaps are a new feature introduced by the standard.
They aren't possible in ARM C++ and I still don't know of any current
compiler that supports them. They are an unproven innovation.

In my view, anyone proposing to add const heaps to the standard should
have been obliged to show how that could be done without breaking the
existing const type-safety. As with any new feature.

  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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/04/13
Raw View
In article <memo.19990406134514.27141B@btinternet.com>,
  brangdon@cix.co.uk wrote:
> jim.hyslop@leitch.com (Jim Hyslop) wrote:
> > Well, from that point of view, then *creating* a const object (or,
> > shall we say, an object that will be const) should also be
> > disallowed because you are attempting to modify a constant object.
>
> But that is not attempting to modify a const object at all. It is
> attempting to modify an object that will become const later. Your
> situation is analogous to:
>
>     Object *pv = new Object;
>     pv->nonConstMethod();   // Legal?
>     const Object *pc = pv;

> An object does not become const until its constructor is finished.
And when does it *cease* to be const?  You cannot define only half of the
equation - you must define the entire life cycle.  When does a constant object
cease to be const?

There is only one possible answer: Immediately before the destructor begins.
Well, this begs the question - can you call a destructor on a const object?  I
say yes, because control over an object's lifetime is what 'new' and 'delete'
are all about.

OK, let's say for a moment that the Committee had voted the other way - how
would you express the idea that you want to have a pointer to an object that
you don't want modified; that pointer is created by a factory method which
means two things: a) you cannot directly instantiate the class, you have to
get a pointer to it from the factory; b) you must delete the class or a
memory leak will occur.  For example:

// class T defined somewhere
void func()
{
   const T *t=T::Create(something); // 'something' indicates
                                    // which type to instantiate
   // use t somehow, but do not allow it to be modified
   delete t; // oops - not allowed by your scenario.
}

The only way I can think of is to use two pointers:
void func()
{
   T *t=T::Create(something);
   const T *constT=t;
   // use constT, not t
   delete t;
}

Rather awkward, isn't it?

-----
Jim
I ignore all email from recruitment agencies.
Please do not send me email with questions - post here.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/04/13
Raw View
In article <memo.19990409183231.5569G@btinternet.com>,
  brangdon@cix.co.uk wrote:
[snip]
> This is crucial. In my view, only objects which can be modified are
> suitable arguments for operator delete(). This means that "dynamic" and
> "const" are not independent after all - "const" objects cannot be
> "dynamic".

I agree with Andrew's assessment.  There are in fact two separate concepts
being expressed by the current usage of const.

If I create an object using new, why can I not destroy that object using
delete? Why force me into a hackish workaround for this:

void foo()
{
   const T *t=T::Create(something); // Returns a pointer to a class derived
                              // from T based on 'something' - an Abstract
                              // Factory, IOW

   // use t somehow
   delete t;
}

I have created t, I don't want it changed during its lifetime, yet there is
nothing about T which would normally prevent me from destroying it.

I also agree with Andrew's other point - with the language as it sits, there
will be no resolving this argument.  I think I'm going to abandon this thread
now.

-----
Jim
I ignore all email from recruitment agencies.
Please do not send me email with questions - post here.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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: Dean Foster <foster@compstat.wharton.upenn.edu>
Date: 1999/04/13
Raw View
> It is possible to declare the function differently, such that it
> guarantees to neither change nor delete the object:
>
>    void proc( const Object& object );
>

It seems that the following is and should be legal:

void
g(const foo &fu)
{
  delete &fu;
};


It doesn't generate any errors on egcs.  I always assumed it would be illegal.
Does the standard say this shouldn't be allowed?

thanks,

dean
---
[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/13
Raw View
ncm@nospam.cantrip.org (Nathan Myers) writes:

>Andrei Alexandrescu<andreia@netzip.com> wrote:
>>I agree that the existence of a genuinely const heap seriously shatters the
>>arguments of the anti-standard participants to this discussion. Someone
>>quoted from the standard that "calling the new operator on a cv-qualified
>>type returns a pointer to a cv-qualified type", which at least leaves room
>>for implementing a const heap.
>
>Not quite.  There is no argument to operator new() to tell it
>that the object is to be const, so should be placed in a write-
>protected page.  A user- or vendor-defined operator new() could
>have such an argument, but then regular delete could not be
>used on the object.

Implementing const heap objects would not require any extra
argument to operator new() to indicate constness.  Indeed,
I don't see how any such argument could help, since the memory
isn't read-only after it has been allocated -- it doesn't become
read-only until after the constructor has finished.

Instead, implementing const heap objects would require a
fine-grained equivalent to mprotect(), and perhaps an
additional implicit arguments to the constructor.
The compiler could insert

 if (__is_const) make_read_only(this, sizeof(*this));

at the end of every constructor, where `__is_const' is the
name of the implicit parameter passed to the constructor, and

 make_writeable(this, sizeof(*this));

at the start of every destructor.  Or alternatively the calls to
make_read_only() and make_writeable() could be generated at the places
which call a constructor or destructor, rather than inside the
constructor or destructor (this would avoid the need for the implicit
`__is_const' parameter to the constructor).

>>So from now on, whenever someone brings up an argument against the standard
>>in this issue, a solution to the const heap issue should be brought up as
>>well.
>
>Because of the problems, a const heap is purely theoretical
>and can can only confuse matters.

I don't know exactly what problems you are referring to.  As far as I
know there is only one problem, which is the presence of the words
"with static or automatic storage duration" after "const object" in the
wording in 3.8 - Object Lifetime [basic.life], paragraph 9.

Personally I think including those words was a bad decision.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/13
Raw View
scorp@btinternet.com (Dave Harris) writes:

>If the standards committee wanted to introduce const heaps, that would
>have been a reasonable way to go. Although it doesn't sound as though they
>thought of it in those terms, which makes this line of argument moot.

Some of us on the standards committee certainly thought of it in those
terms, and did indeed want to allow implementations to write-protect
memory on the heap.  This was definitely discussed by the working-group
involved (I was there).  And it was one of the motivations for allowing
deletion of const objects -- though by no means the only one.

>But seriously, I think you're misplacing the burden of proof. As I
>understand it, const heaps are a new feature introduced by the standard.

That is not really a correct understanding.  Unfortunately the committee
did not quite go far enough.  The wording in 3.8 paragraph 9 about
reusing the memory occupied by const objects is restricted to objects
with static or automatic storage duration.  This makes it very difficult
(though not entirely impossible) for an implementation to write-protect
heap objects.

>They aren't possible in ARM C++

Well, this is not entirely clear.
Technically, the following code is valid ARM C++:

 typedef const int CI;
 CI *p = new CI(42);

Furthermore ARM 7.1.6 says

 A const object of a type that does not have a constructor
 or destructor may be placed in readonly memory.

>and I still don't know of any current
>compiler that supports them. They are an unproven innovation.
>
>In my view, anyone proposing to add const heaps to the standard should
>have been obliged to show how that could be done without breaking the
>existing const type-safety. As with any new feature.

Let's not rewrite history here.  The "existing const type-safety"
already allowed destruction of const objects, and as I argued above,
technically the ARM did allow read-only heap objects (even if the
intent was otherwise).

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/13
Raw View
Dean Foster <foster@compstat.wharton.upenn.edu> writes:

>> It is possible to declare the function differently, such that it
>> guarantees to neither change nor delete the object:
>>
>>    void proc( const Object& object );
>
>It seems that the following is and should be legal:
>
>void
>g(const foo &fu)
>{
>  delete &fu;
>};

Yes, that's correct.  That code is well-formed and quite legal.

However, it is also quite poor style, IMHO.
If the function might delete its argument then it is better
style to pass it a pointer rather than a reference.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ 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" <andreia@netzip.com>
Date: 1999/04/13
Raw View
Nathan Myers <ncm@nospam.cantrip.org> wrote in message
news:7etnpk$1r0$1@shell7.ba.best.com...
> Not quite.  There is no argument to operator new() to tell it
> that the object is to be const, so should be placed in a write-
> protected page.

Yes it is. I learned that:

class T {};
const T * p = new const T;

is legal code, and it passes enough information to the compiler to place the
object in a constant heap. At least that's my understanding.

> >On the other hand, delete-ing const object has several disdvantages,
which
> >leads to quite an unpleasant state of affairs.

Thank for correcting my typo :o).

> The language is _not_ going to be fixed.
> However, better warnings would be almost as good.  There are three:
>
>   warning: destructor call on pointer-to-const
>   warning: destructor call on reference-to-const
>   warning: delete of pointer-to-const

I like that.

Andrei
---
[ 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/04/13
Raw View
Dean Foster wrote:
>
> > It is possible to declare the function differently, such that it
> > guarantees to neither change nor delete the object:
> >
> >    void proc( const Object& object );
> >
>
> It seems that the following is and should be legal:

I believe that it is.

> void
> g(const foo &fu)
> {
>   delete &fu;
> };
>
>
> It doesn't generate any errors on egcs.  I always assumed it would be illegal.

Did you mean "legal"?

> Does the standard say this shouldn't be allowed?

Not as far as I can tell.
---
[ 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/04/14
Raw View
Dave Harris<brangdon@cix.co.uk> wrote:
>jim.hyslop@leitch.com (Jim Hyslop) wrote:
>> OK, let's say for a moment that the Committee had voted the other way -
>> how would you express the idea that you want to have a pointer ...
>> created by a factory method ...
>> you must delete the class or a memory leak will occur.

This was the original issue, and has been dealt with already.

>> [...]
>> The only way I can think of is to use two pointers:
>
>Use a wrapper class. It would contain a private non-const pointer exposed
>only as a const pointer, plus a function to delete. Such a wrapper class
>could be written once, as a template, and added to a library.

The much-simpler solution is for the factory itself to provide
another method to dispose of the instance it constructed.  There
might be other reasons to use a wrapper class, however.

--
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/04/14
Raw View
David R Tribble <dtribble@technologist.com> wrote:
>Dave Harris <brangdon@cix.co.uk> wrote:
>>> The main motivation for allowing it seems to be cases like: [...]
>>> where we are imitating auto scope.
>Andrew Koenig wrote:
>> That argument is not particularly important in that particular form.
>> The form that is important is [template where T might be "const U"]
>
>As to Andy's template example, it is definitely a problem.

No, it is not.

In fact, it has been neatly disposed of, several times
in this thread alone.  Do you need to see it again?

  template <class T>
    void const_deleter(T const* p) { delete const_cast<T*>(p); }

--
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/04/14
Raw View
<sirwillard@my-dejanews.com> wrote:
> ark@research.att.com (Andrew Koenig) wrote:
>> But we don't have dynamic.  So the question is how this attribute should
>> be expressed within the C++ type system.  There seem to be two alternatives:
>>  1. Link it to const.
>>  2. Don't express it in the type system.
>
>That said, I think we're back to the original point here.

Exactly: it begs the question, and reveals nothing.  The only reason
anybody tried to separate lifetime from constness was the easy syntactic
distinction.  Experience shows that the semantic distinction is not
nearly so neat, if indeed it is meaningful at all.

>Even if
>one likes option 1) above (basically that you can't delete a const
>object), I fail to see how such a ruling can be considered "intuitive".
>It means that you follow different rules for dynamic objects than
>you do for local objects (meaning that the destructor can be called
>on const objects for local types).  This is hardly intuitive.

Again, this argument, like most that have been presented in favor
of the status quo, begs the question.  Did the ARM define different
rules for local and dynamic objects?  No.

Arguments that something is good or bad because it is or is not
"intuitive" are meaningless when others have different intuition.
Stick to actual consequences, please.

>Therefore, option 2) above seems to be the "logical" choice, and
>the one adopted by the standard, like it or not.

There is no disagreement about what the standard says; the issue is
whether it is broken.

The fact is that the only practical effect of fixing the const hole
would be the addition of a few error messages to the compiler, and of
const_cast<>s in some code to satisfy the compiler in places where
inspection reveals there is no error.

Fortunately, warnings can be added to compilers to compensate for
the design error in the standard.

What is much more worrisome to me is the degree of seriously unsound
reasoning demonstrated (repeatedly!) by people arguing in favor of
the error.  The outline is:

1. Create a false distinction.
2. Discover problems in applying the false distinction.
3. Resolve the problems by destroying something.

This is a mode of action more familiar in politics than in
engineering practice, and I'm disappointed to encounter it here.

--
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: murray-paul@usa.net (Paul Murray)
Date: 1999/04/14
Raw View
On 07 Apr 99 15:07:58 GMT, Andrew Koenig <ark@research.att.com> wrote:
>> In place of a language rule, we are left with a much weaker
>> coding-style rule: "it's a mistake to delete a pointer to a
>> const object you are passed, because the caller might still
>> be using the object."
>It is a mistake to delete a pointer to any object you are passed,
>const or not, unless you know that no one else is using the object.
>I see no reason to single out this particular instantiation of the rule.

As a simple user, I would view a function defined as
void f( const T* t );
as promising not to change the object t, so I can safely call it and know
that it will not affect t. For the function to be able to delete t seems
to violate that quite gratuitiously.

-Paul Murray
---
[ 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" <andreia@netzip.com>
Date: 1999/04/14
Raw View
Paul Murray <murray-paul@usa.net> wrote in message
news:slrn7h8qdk.47h.murray-paul@unix3.netaxs.com...
> On 07 Apr 99 15:07:58 GMT, Andrew Koenig <ark@research.att.com> wrote:
> >> In place of a language rule, we are left with a much weaker
> >> coding-style rule: "it's a mistake to delete a pointer to a
> >> const object you are passed, because the caller might still
> >> be using the object."
> >It is a mistake to delete a pointer to any object you are passed,
> >const or not, unless you know that no one else is using the object.
> >I see no reason to single out this particular instantiation of the rule.
>
> As a simple user, I would view a function defined as
> void f( const T* t );
> as promising not to change the object t, so I can safely call it and know
> that it will not affect t. For the function to be able to delete t seems
> to violate that quite gratuitiously.

Right. I repeatedly tried to point this out. I don't understand why some
people just ignore this serious problem and back the standard up "no matter
what".
To me, the discussion would be much more fruitful if everybody recognized
we're not talking about a hoax here, and would try to sincerely weight
arguments on both sides.

It became obvious to me that const-delete cannot be banished punctually; the
semantics of the new operator would have to be changed as well (new applied
to a const type should return a non-const type).

Also it became obvious that it would create some illegal templates uneasy to
work around, although I think they tend to be rare. However, Andrew Koenig
said this would be a problem in teaching and I'd better believe him.

For now, a warning would be an acceptable fix for now. After reading this
thread, I truly hope this problem will be discussed as part of the next
revision to the standard.

Andrei
---
[ 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 <dtribble@technologist.com>
Date: 1999/04/15
Raw View
Nathan Myers wrote:
>
> Dave Harris<brangdon@cix.co.uk> wrote:
> >jim.hyslop@leitch.com (Jim Hyslop) wrote:
> >> OK, let's say for a moment that the Committee had voted the other
> >> way - how would you express the idea that you want to have a
> >> pointer ... created by a factory method ...
> >> you must delete the class or a memory leak will occur.
>
> This was the original issue, and has been dealt with already.
>
> >> [...]
> >> The only way I can think of is to use two pointers:
> >
> > Use a wrapper class. It would contain a private non-const pointer
> > exposed only as a const pointer, plus a function to delete. Such a
> > wrapper class could be written once, as a template, and added to a
> > library.
>
> The much-simpler solution is for the factory itself to provide
> another method to dispose of the instance it constructed.  There
> might be other reasons to use a wrapper class, however.

That was my first thought, too: if a class provides a factory
creation function Foo::create(), it ought to also provide a
disposal function Foo::destroy().  But this doesn't solve the
problem of how to delete through a pointer-to-const - how do you
declare the destroy() function to take either a 'Foo *' or a
'const Foo *'?

If you declare it as taking a 'const Foo *', it has to cast away
the const in order to call the delete operator (assuming this is
how C++ /should/ do it).  You've also broken the implied guarantee
that a function passed a pointer-to-const won't modify the const
object - although this could be considered proper since the
function in question is a disposal function.

    Foo * Foo::create()
    {
        ...
    }

    void Foo::destroy(const Foo *o)     // [A]
    {
        delete const_cast<Foo *>(o);    // [B]
    }

    void myFunc()
    {
        const Foo *  f = Foo::create(); // [C]
        ...
        Foo::destroy(f);                // [D]
        f = NULL;
    }

-- David R. Tribble, dtribble@technologist.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: "J.Barfurth" <techview@bfk-net.de>
Date: 1999/04/15
Raw View
Nathan Myers schrieb in Nachricht <7erjjk$45v$1@shell7.ba.best.com>...
>(Joerg, please arrange so that your news poster does not scramble
>your text.  It is hard to read, and hard to reply to.)
>
>Joerg Barfurth <jbarfurth@vossnet.de> wrote:
>>We can extend the original form to the case
>>  void proc()
>>    { const Object* p =3D factory->CreateReadOnly(); delete p; }
>>
>>After all it is the possibility of polymorphism, that distinguishes
>>pointers from locals. Here the (logical) constness of the object is
>>entirely distinct from lifetime issues.
>
>In that case the canonical form is
>
>  void proc()
>    { const Object* p =3D factory->CreateReadOnly();
>      factory->Dispose(p); }
>
>In other words, Joerg's example is an argument _in_favor_of_ the ARM
>rule, because the above usage is otherwise impossible to enforce without
>smart pointers.

But
  void proc2()
    { Object* p =3D factory->CreateModifiable();
      delete p; }
Here the above usage _is_ impossible to enforce (at least that simply). I=
t
can be enforced by using aprivate/protected destructor or class operator
delete. But that works for const and non-const pointers alike.

I still maintain, that the compiler should not disallow me to handle
lifetime issues separately from constness issues. In my original example =
the
pointer received by proc could be stored away somewhere else. Then later
when I'm really through using it, I might not have the proper 'factory'
available. A factory is in charge of creating and initializing an object =
of
the correct dynamic type because client code may not know about the dynam=
ic
type or correct initialization.

Destroying the object is different from creation: destructors don't have
parameters, there are no provisions for placement in delete-expressions;
instead destructors can be virtual. So the object should know how to
properly destroy itself and cleanup any resources, not the code that crea=
ted
it or even the context that was the last one using it. This 'owning conte=
xt'
must only know _when_ (and if) it may delete the object, not the dirty
details _how_ to do it.

BTW: offering Factory::Dispose(Object const*) again may crush your
assumptions about the object surving a call to f(Object const*). f may ha=
ve
access to a Factory. I can't see any real difference between calling a
designated Dispose function and directly invoking operator delete. (OK, y=
ou
can search for occurrences of "Dispose").

-- J=F6rg Barfurth
---
[ 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: "John D. Hickin" <hickin@Hydro.CAM.ORG>
Date: 1999/04/15
Raw View
Nathan Myers wrote:
>

>
> The much-simpler solution is for the factory itself to provide
> another method to dispose of the instance it constructed.  There
> might be other reasons to use a wrapper class, however.
>

I can see that an auto_ptr-like template is required if we are to
maintain the same degree of exception safety that was available for free
in the example void f() { const X x; ... }.

Now the X on heap version looks like this:

  void f() {
    auto_ptr_like_thing<X> apX( new X ); // auto_ptr_like_thing<const X>
would also do
    const X* pX = apX.get();
    ...
  }

The call on get() will be required in cases where template deduction on
the type is required as you have pointed out elsewhere, and that, I
believe, seals the argument in favour of the old rule: on the one hand,
any const_cast<>ing may be safely buried in the template implementation,
while on the other, much of the safety afforded us through the use of
the wrapper is lost if we are allowed to delete through pX.


Regards, John.
---
[ 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/04/15
Raw View
Nathan Myers wrote:
....
> BTW, my use of the term "fraudulent" has raised tempers, and I
> apologize.  The usage was an allusion to a remark by bs in D&E:
> "argument by analogy is fraud".  Probably that expression should
> be limited to referring to one's own straw arguments.

Not even that - argument by analogy is a perfectly reasonable technique,
which like any other technique, can be misused. I don't think it's being
misused in this context.
Even when it's being misused, the user is usually himself decieved by
the argument. If so, the user isn't guilty of fraud, merely of
stupidity.
---
[ 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/04/15
Raw View
Siemel Naran wrote:

[...]

> >- The difference between { T const* p = new T(); delete p; } and { T const
> >t; } is moved to where it obviously exists: memory (de-)allocation.
>
> Ok.  But if you wanted the explicit call of a destructor to be illegal
> too, that would be ok with me!  Sure, it's somewhat illogical, but it
> does make C++ safer.

I consider an explicit constructor call a moral equivalent to a cast.
Since you can circumvent C++ const safety with a cast, there's no
problem with the explicit destructor call.

Granted, you can actually modify a const object through destructor
calls, like

void f(X const* p)
{
  p->~X();
  new(p) X(0.8/15, 4711);
}

However, you also can do

void f(X const* p)
{
  *const_cast<X*>(p)=X(0.8/15, 4711);
}

[...]
---
[ 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: ajonas@my-dejanews.com
Date: 1999/04/15
Raw View
Nathan Myers Wrote:
> The result is that a whole class of preventable errors are
> not caught by a standard-conforming compiler, and it is now
> impractical to warn about them either.  This is unfortunate.
> C++ does show some evidence of "design by committee", and this
> is one of the more egregious, because it is so gratuitous.

I feel that more errors could have been prevented if there was a keyword
available to indicate lifetime of a pointer. For wan't of a better
keyword(s), 'immortal/mortal'. Deleting a pointer to const seems to be a
minor problem compared to deleting auto and static variables. I assume there
are good reasons why such a keyword doesn't exist, but without it, the
meaning of const will remain debatable. My preference is that 'const' means
'mortal const'.

Examples:

class X {};

void a(mortal   const X* p) { delete p; } // Legal
void b(immortal const X* p) { delete p; } // Illegal
void f(void)
{
    X p;
    delete &p;        // Illegal. &p is immortal
    mortal X* q = &p; // Illegal
    a(&p);            // Illegal
}

---
Alex Jonas

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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/04/13
Raw View
jim.hyslop@leitch.com (Jim Hyslop) wrote:
> OK, let's say for a moment that the Committee had voted the other way -
> how would you express the idea that you want to have a pointer to
> an object that you don't want modified; that pointer is created by
> a factory method which means two things: a) you cannot directly
> instantiate the class, you have to get a pointer to it from the
> factory; b) you must delete the class or a memory leak will occur.
> [...]
> The only way I can think of is to use two pointers:

Use a wrapper class. It would contain a private non-const pointer exposed
only as a const pointer, plus a function to delete. Such a wrapper class
could be written once, as a template, and added to a library.

  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/04/13
Raw View
celtschk@physik.tu-muenchen.de (Christopher Eltschka) wrote:
> Yes, it is an alias. But it's a non-const access path to a
> const object, without any cast. Therefore it can be considered
> a const hole.

Absolutely. You can use it to call any non-const method, not just operator
delete(). I don't see how it affects the argument. Do you think that the
existence of this hole means that we should remove all restrictions on
calling const functions? If not, then what is it about your example that
justifies a special pleading for removing restrictions on operator
delete() alone?


> Note that only the constructor and destructor have a non-const
> pointer to a const object. There's no other way to obtain such
> an access path without a cast.

Again, I quite agree. In particular, to exploit this hole you need help
from inside the class - you need to be the person who wrote the
constructor. One supposes the class author knew what she was doing, had a
good reason to break encapsulation. It is not like operator delete() which
can be called from outside the class. To me this means that the loop hole,
although regrettable, is not as serious as that added by the delete rule.

  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: Dean Foster <foster@compstat.wharton.upenn.edu>
Date: 1999/04/13
Raw View
Fergus Henderson wrote:
>
> Dean Foster <foster@compstat.wharton.upenn.edu> writes:
>
> >> It is possible to declare the function differently, such that it
> >> guarantees to neither change nor delete the object:
> >>
> >>    void proc( const Object& object );
> >

> However, it is also quite poor style, IMHO.

Thats an understatement!

My understanding of a "const foo&" was that it was supposed to be a more
efficient way of passing arguments over copying.  Basically a way of doing
functional programming without having to copy large objects.  So, the semantics
of:

  f(const foo&)

and

  g(foo)

should be very close to the same.  So I was shocked when the const pointer could
be deleted.  But, that a const foo& might not make it back alive really blows me
away.

I guess I'm coming down on the side of the standard shouldn't allow deleting
const pointers.

My only other idea of how to at least make "const foo&" safe would be to
disallow taking its address.  Now that is a suggestion that would break at least
300 lines of my 50k line project I'm working on.  So I wouldn't be very happy
with it.

thanks,

dean
---
[ 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/04/14
Raw View
fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> >They aren't possible in ARM C++
>
> Well, this is not entirely clear.

I understood the argument as saying that we can't have a const heap unless
there is a way to delete const objects. The ARM is very clear on that
($5.3.4):

    A pointer to constant cannot be deleted.

(And there is lovely commentary explaining why.) If you have a way to have
a const heap *without* changing the ARM rule, surely the argument for
changing the rule doesn't apply? What am I missing?

I don't mean to rewrite history. Unlike you I wasn't there, so I'm trying
to understand it retrospectively. But it's hard to reconcile what people
are saying.

  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: David R Tribble <dtribble@technologist.com>
Date: 1999/04/14
Raw View
Dave Harris <brangdon@cix.co.uk> wrote:
>> The main motivation for allowing it seems to be cases like:
>
>>     void proc() {
>>         const Object *pObject = new Object;
>>         //...
>>         delete pObject;
>>     }
>
>> where we are imitating auto scope.

Andrew Koenig wrote:
> That argument is not particularly important in that particular form.
> The form that is important is
>
>         template<class T> void proc(args) {
>                 T *tp = new T;
>                 // ...
>                 delete tp;
>         }
>
> Now, you don't know whether T is a const type.  If you could not say
> "delete tp;" directly, there is no cast you could write that would
> allow it.

After lurking on this thread for a while, I'm now on middle ground.
I admit that it is more convenient to be able to 'delete p' directly
without a const_cast<>(), but I also admit that allowing deletes
of pointers-to-const can let some errors slip by that rightfully
should be caught by the compiler.

As to Andy's template example, it is definitely a problem.
Unless we allow an exception in the typing system.  Namely, that
we make it illegal to delete a pointer-to-const unless the pointer's
type is derived from a template type parameter.  So Dave's example
would result in a compiler warning (or error), and Andy's example
would compile just fine.

An alternate approach is to make
   const_cast<T*>(tp)
mean that we are removing the constness from tp, provided that
T is a template type parameter, and make
   const_cast<const T*>(tp)
mean that we are adding constness to tp under the same provision.
If T is not a template type parameter, const_cast<>() acts as
it does now.

Would either of these suggestions settle the issue?

-- David R. Tribble, dtribble@technologist.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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/04/11
Raw View
Dave Harris<brangdon@cix.co.uk> wrote:
>sirwillard@my-dejanews.com () wrote:
>> Not to mention the extra coding of what is in essence a hack to
>> work around a poorly defined definition of const.  This concept is ugly
>> [...]
>
>Well, that is a value judgement. There is extra coding, true, but
>achieving const correctness often requires extra coding. Consider methods
>like std::vector<>::begin(), which has to be defined twice, once const and
>once non-const. This is the same.

No.  This is extra coding to define different results for the two cases.
In my experience const correctness does not, and should not, generally
involve extra coding.

>If you don't like the extra work a static type system puts you to, you
>should consider switching to some other language, like Smalltalk.

The static type system should provide extra safety by default, and
require extra coding to circumvent it.  That is what it is for.

In other words, if you find type-safety inconvenient, consider switching
to a language that has less.  It is a shame that C++ was changed to
reduce type-safety in the name of a spurious convenience.

--
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/04/11
Raw View
ncm@nospam.cantrip.org (Nathan Myers) wrote:
> The advantages of linking it to const have been acknowledged.
> So far nobody has presented any disadvantages that withstood
> scrutiny.  (Thank you, Andrei, for the most detailed scrutiny.)
> The only inconvenience discovered was the need for a const_cast<>
> to inform the compiler that you were violating constness, which
> is what const_cast<> is for.

For me the argument of the truly const heap seemed quite strong. This is
the issue of how to deal with code like:

    const Object *p = new const Object;

The idea is that some future implementation might somehow put the object
into ROM despite it being allocated dynamically, and that it might then be
undefined to cast const away (as for static objects). This is verging on
oxymoron, but the syntax has to be dealt with. I can see 4 reasonable
approaches.

----
(1) Forbid it. There is no const heap.

This would require more care when using const in typedefs, and templates
would have to be specialised for const more often. But this is doable.
Other articles in the thread have discussed techniques. I doubt it would a
big problem in practise. At least one major compiler, Microsoft's, does
not allow the syntax today, so it can't be essential. Much code has been
written without it.

----
(2) Allow the syntax, but make it equivalent to:

    const Object *p = new Object;

Again, there is no const heap; casting away const for a heap object is
always well-defined. An implementation may not switch on read-only
hardware for "new const Object" unless it can switch it off again in a
const_cast (which rather defeats the point).

In effect this is (1) but with syntactic sugar to make templates and
typedefs easier. Together with the const template techniques described
elsewhere in the thread, this should be quite workable, if confusing.

----
(3) Allow objects to be allocated from the const heap, but don't allow
them to be explicitly deleted. They become memory leaks until a garbage
collector kicks in, or the program terminates. (Program termination is
also when static const objects get deleted.)

You may think this is unreasonable and inconsistent. I think the
inconsistency is in the idea of the const heap itself; the very notion of
deleting ROM is bizarre. To say it exists (at least) until the end of the
program would be fair.

I also think it is reasonable to use a garbage collector with C++. Look at
it this way: any implementation clever enough to make heap-allocated
objects read-only on the fly should also be clever enough to deallocate
them automatically.

----
(4) Allow a const heap, and provide new mechanisms for dealing with it.
These should be enabled on a class-by-class basis. For example:

    class Object {
    public:
        Object() const;
        ~Object() const;

        // Or:
        void operator delete( const void * );
    }

Or some other syntax (those are squeezing it into existing forms; probably
a bad idea). The idea is that people who had to have const heaps could
have them without causing problems for the rest of us.

----
I accept that none of those approaches is ideal. No doubt people will
point out the flaws in each one. However, I think each of them is better
than the current rule, which I see as catastrophically bad.

  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: "John D. Hickin" <hickin@Hydro.CAM.ORG>
Date: 1999/04/11
Raw View
Nathan Myers wrote:
>
> Andrew Koenig<ark@research.att.com> wrote:
> >Dave Harris <brangdon@cix.co.uk> wrote:
> >
> >> The main motivation for allowing it seems to be cases like:
> >>     void proc() { const Object *pObject = new Object; delete pObject; }
> >> where we are imitating auto scope.
> >
> >That argument is not particularly important in that particular form.
> >The form that is important is
> >       template<class T> void proc(args) { T *tp = new T; delete tp; }
> >Now, you don't know whether T is a const type.  If you could not say
> >"delete tp;" directly, there is no cast you could write that would allow
> >it.
>
> NB This argument has already been neatly disposed of.  A helper
> template, or for full generality a traits class template, does
> the job.
>

I think that we have all lost sight of the possibility that a suitable
class design might also eliminate the dangers associated with delete.
If, for example, we make use of something like this:

  template<class T>
  class Ptr {
    T* m_Ptr;
    operator void*();
  public:
    operator T*() const { return m_Ptr; }
    etc.
  };

we can avoid the return of a bare T* fram any accessor in a class X:

  class X {
  ...
  public:
    Ptr<const T> ptr();
  };

because delete through X::ptr() is ambiguous.

Now that each point of view may be fixed up by the use of a suitable
template what way is there to prefer one over the other?

Regards, John.
---
[ 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: Joerg Barfurth <jbarfurth@vossnet.de>
Date: 1999/04/11
Raw View
Nathan Myers wrote:
> =

> Andrew Koenig<ark@research.att.com> wrote:
> >Dave Harris <brangdon@cix.co.uk> wrote:
> >
> >> The main motivation for allowing it seems to be cases like:
> >>     void proc() { const Object *pObject =3D new Object; delete pObje=
ct; }
> >> where we are imitating auto scope.
> >
> >That argument is not particularly important in that particular form.
> >The form that is important is
> >       template<class T> void proc(args) { T *tp =3D new T; delete tp;=
 }

We can extend the original form to the case
 void proc() { const Object* p =3D factory->CreateReadOnly(); delete p; }=

After all it is the possibility of polymorphism, that distinguishes point=
ers
from locals. Here the (logical) constness of the object is entirely disti=
nct
from lifetime issues.

> >Now, you don't know whether T is a const type.  If you could not say
> >"delete tp;" directly, there is no cast you could write that would all=
ow
> >it.
> =

> NB This argument has already been neatly disposed of.  A helper
> template, or for full generality a traits class template, does
> the job.

Let me first state, that I don't like the idea that the compiler is allow=
ed to
do many things, that the I am not allowed to do, behind my back. You and =
other
posters on this thread strongly suggest, that the compiler is given such
rights. I cannot see any places though, where the compiler is allowed to
violate constness or member access for instance. Of course the compiler m=
ay do
things differently from what the I can do (explicitly). But as far as suc=
h
behaviour concerns semantics within the realm of the standard, such 'hidd=
en
mechanics' are still governed by the as-if rule.

- allowing destructor calls on const objects [12.4 paragraph 2] we avoid
unnecessarily granting the right to violate constness to the compiler (fo=
r
static/automatic objects). =

So any reasons for disallowing delete on a pointer to const should be fou=
nded
in the objects' storage duration. The compiler can do special things when=

allocating and deallocating raw memory (e.g. for auto objects) as the
mechanics of this are beyond the scope of the language. Differences betwe=
en
objects of static/auto and dynamic storage duration should be related to =
the
presence/absence of allocation functions and to the fact that an objects
storage duration is known at compile time.

- as constness is a property of an object only during it's lifetime
[basic.life] it shouldn't apply to storage duration [basic.stc], which
generally is longer than lifetime.


Also I think that simplicity in basic rules is important.

- it seems natural, that the type of 'new const T' would be 'const T *'. =
I
admit that a rule to the effect,that toplevel const is ignored in
new-expressions, is
reasonably simple, but IMHO it would still be counterintuitive. How else =
could
I state, that an object of dynamic storage duration shall not be modified=

during its lifetime.

- Storage created by new-expressions, can be deleted with delete-expressi=
ons.
This rule holds at least as long as I don't explicitly try to take over
memory management by overriding/overloading any operator new/delete. =

Note that, referring to storage allocation, I disregard the special case =
of
operator new(size_t,void*).

- It doesn't seem natural that some pointers (though simply new'ed origin=
ally)
can only be deallocated using a template function, which moreover _promis=
es_
to violate const when give a chance.(The traits approach wouldn't change =
much.

It appears to me, that the desire to disallow delete for const pointers
partially goes back to the C programming language. In ANSI/ISO C you inde=
ed
may not free (by standard mechanisms) memory using a const pointer. So th=
is
actually is a point where the guarantees given by const in C++ are weaker=
 than
those that had existed in C alone. OTOH in C there is no distinction betw=
een
logical constness of objects and (bitwise) constness of the storage they
occupy. In C++ there are various areas in which constness of the underlyi=
ng
storage has been dropped in favor of logical constness of objects (which =
is
restricted to their lifetime).

Actually the standard (as it is today) seems to be rather consistent in t=
his
respect, except for one 'defect': To avoid an unnecessary implicit const_=
cast,
the first parameter of operator delete should be of type 'void const *'. =
This
seems strange at first, but that feeling is caused by experience with
malloc/free and prestandard C++. It becomes more natural once we stop
envisioning constness as a property of storage. Any action the compiler o=
r the
OS might take to mark memory free for (their) reuse are beyond the scope =
of
the language requirements (and thereby beyond 'const'). But of course thi=
s
change would be hard to do consistently. Extending it to user defined ope=
rator
delete would break a lot of existing code.  Restrictions such as [3.8 p. =
9]
then are concessions to allow 'storage constness' in cases where the
relationship between storage duration and lifetime (in the normal case,
disregarding reuse of storage or const_cast) is fully visible (to compile=
r and
user) at compile time.

If we try to make 'const' represent a compound concept comprising some
assertions about lifetime and/or storage duration besides the current
'non-modifiable during lifetime' rule, it would even be difficult to exac=
tly
state these additional assertions. Changing the meaning of 'const' this w=
ay
(disallowing f.i. delete pointer-to-const) would IMHO require major chang=
es to
the standard, if the new meaning of 'const' is supposed to be reflected
correctly everywhere. =


-- J=F6rg
---
[ 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/04/12
Raw View
John D. Hickin<hickin@Hydro.CAM.ORG> wrote:
>Nathan Myers wrote:
>> Andrew Koenig<ark@research.att.com> wrote:
>> >
>> > The main motivation for allowing it seems to be cases like:
>> >       template<class T> void proc(args) { T *tp = new T; delete tp; }
>> >Now, you don't know whether T is a const type.  If you could not say
>> >"delete tp;" directly, there is no cast you could write that would allow
>> >it.
>>
>> NB This argument has already been neatly disposed of.  A helper
>> template, or for full generality a traits class template, does
>> the job.
>
>I think that we have all lost sight of the possibility that a suitable
>class design might also eliminate the dangers associated with delete.

No, that has been discussed.  That was the "smart pointer" suggestion.
There are as usual many possible variations.

>If, for example, we make use of something like this:
>  template<class T>
>    class Ptr { [ two different conversions to pointer types ] };
>we can avoid the return of a bare T* fram any accessor in a class X
>because delete through X::ptr() is ambiguous.
>
>Now that each point of view may be fixed up by the use of a suitable
>template what way is there to prefer one over the other?

Yes.  Two reasons:

1. The default should be safe.  The suggestion requires extra code to
   achieve the safety of the ARM rule, with no corresponding benefit
   other than an actually-spurious convenience.

2. The template smart pointer suggested is not usable as an argument
   to a template function which much deduce facts about the pointer.

--
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/04/12
Raw View
(Joerg, please arrange so that your news poster does not scramble
your text.  It is hard to read, and hard to reply to.)

Joerg Barfurth <jbarfurth@vossnet.de> wrote:
>Nathan Myers wrote:
>> Andrew Koenig<ark@research.att.com> wrote:
>>>The form that is important is
>>>    template<class T> void proc(args) { T *tp = new T; delete tp; }
>
>We can extend the original form to the case
>  void proc()
>    { const Object* p = factory->CreateReadOnly(); delete p; }
>
>After all it is the possibility of polymorphism, that distinguishes
>pointers from locals. Here the (logical) constness of the object is
>entirely distinct from lifetime issues.

In that case the canonical form is

  void proc()
    { const Object* p = factory->CreateReadOnly();
      factory->Dispose(p); }

In other words, Joerg's example is an argument _in_favor_of_ the ARM
rule, because the above usage is otherwise impossible to enforce without
smart pointers.

>>>Now, you don't know whether T is a const type.  If you could not say
>>>"delete tp;" directly, there is no cast you could write that would
>>>allow it.
>>
>
>> NB This argument has already been neatly disposed of.  A helper
>> template, or for full generality a traits class template, does
>> the job.
>
>Let me first state, that I don't like the idea that the compiler is
>allowed to do many things, that the I am not allowed to do, behind
>my back. You and other posters on this thread strongly suggest, that
>the compiler is given such rights. I cannot see any places though,
>where the compiler is allowed to violate constness or member access
>for instance.

You are allowed to do precisely the same things, but with a
const_cast<>.  Assume, if you like, that the compiler-generated
code contains all the necessary const_cast<>s.

The compiler already provides reinterpret_cast<>s for you:
one in each constructor.

>- allowing destructor calls on const objects [12.4 paragraph 2] we avoid
>unnecessarily granting the right to violate constness to the compiler
>(for static/automatic objects).

Why are you reluctant to grant the compiler the right to do what
is proven to be necessary and safe?  It does this in many, many
other ways.

>So any reasons for disallowing delete on a pointer to const should be
>founded in the objects' storage duration. [...]
>
>- as constness is a property of an object only during it's lifetime
>[basic.life] it shouldn't apply to storage duration [basic.stc], which
>generally is longer than lifetime.

This begs the question.  The issue is whether deletion or destruction
-- ending the lifetime -- should be permitted for a pointer-to-const.
The evidence is that the permission is bought at an extremely heavy
cost.

>Also I think that simplicity in basic rules is important.

As do we all.   However, reasoning from first principles in this
way doesn't seem to lead to simple consequences.  Maximizing const
safety has quite simple and demonstrably desirable consequences.

> [lots of interesting but scrambled text snipped]

>If we try to make 'const' represent a compound concept comprising
>some assertions about lifetime and/or storage duration besides the
>current 'non-modifiable during lifetime' rule, it would even be
>difficult to exactly state these additional assertions.

Except that this was the original condition of the language for
almost ten years.  There were no real problems noticed.  The
separation of constness from lifetime was suggested by the
purely-incidental separability of the syntax.

>Changing the meaning of
>'const' this way (disallowing f.i. delete pointer-to-const) would
>IMHO require major changes to the standard, if the new meaning of
>'const' is supposed to be reflected correctly everywhere.

It did not require major changes to the standard when the decision
was made to change to the status quo.  Changing back would be no
harder (not that there is any real possibility of that).

What *is* possible now is for better-quality compilers to warn about
destroying objects through pointers/references-to-const, whether by
explicit destructor call or by a delete-expression.  This will add
no "major" complications, and its only difference from the effect of
actually fixing the language is that they are warnings instead of
errors.

--
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: kramsay@aol.com (KRamsay)
Date: 1999/04/12
Raw View
In article <7elbcd$mbb$1@shell7.ba.best.com>, ncm@nospam.cantrip.org (Nathan
Myers) writes:
|The real issue is, what is const for?  It should provide the strongest
|possible guarantees about the sanctity of the object it protects, so
|that we need not fear releasing a T const* pointer to the world-at-large.

That seems basically a good way to sum up the reason for the old rule.
The strongest possible guarantee would have to include that the object
is permanent, though, which the old rule doesn't do.

|Otherwise it's hard to say what it _is_ good for.

Once one has dealt with ensuring the lifespan of an object (however
you do it), it ensures that the object doesn't change during it
(without deliberate efforts to make it do so).

In article <37111F45.DC86D57A@vossnet.de>, Joerg Barfurth
<jbarfurth@vossnet.de> writes:
|If we try to make 'const' represent a compound concept comprising some
|assertions about lifetime and/or storage duration besides the current
|'non-modifiable during lifetime' rule, it would even be difficult to
|exactly state these additional assertions.

My feeling while reading the discussion is that when I try to state in
my own mind what the old "const" rule *means* about how objects behave,
my brain keeps getting dragged back into a procedural programming way
of thinking. I guess "...and only the compiler can destroy it" is about
the neatest way of saying it.

In the good old days, when I was just getting started, I learned these
languages where the compiler arranges for all the objects to last from
the initiation to the termination of the program, and then some
programming styles in other languages where the duration of an object
is neatly tied to things like the execution of a block of code.

Then things got interesting. There was a definite shift from "the
compiler takes care of object lifetimes for you" to "you get to watch
out for object lifetimes yourself". I no longer feel this implicit
trust that the compiler's facilities will handle lifetimes in an
automatic way. It helps you some, but it's not a very good "owner" of
your objects.

If I need to *prevent* an object from being destructed by some random
code out there, my knee-jerk reaction is to want to keep the destructor
from being callable "out there". What I really want is to be in control
of the lifespan, including not *having* to keep anything around any
longer than I want it to remain around. Meanwhile, I do like having
const to help me assert how it ought to behave while alive.

I'll second the idea that more empirical experience would be worth a
lot of theoretical reflection here. (Have *any* "disasters" occurred
due to either the old rule or the current one?) I prefer empirical
evidence much less strongly than some people would, though. I think
part of why people have the experiences they have with programming is
that they have a certain conception in mind of what they're doing, as
they're doing it. One is testing hypotheses about the interaction
between programmers, computers, and users, and in principle all the
variables have to be taken into account. This means, in particular,
that how well a language construct "works" may depend upon what kind
of mental model programmers have already developed for it. I've seen
occasions when ideas fail to "work" for people (while they "work" very
well for others) because of interference from preexisting habits of
thought. But this means that until the conceptual issues have been
sorted out, the empirical experience is not entirely trustworthy
either.

Keith Ramsay
---
[ 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" <andreia@netzip.com>
Date: 1999/04/12
Raw View
Good analysis.
There is a slight mistake, I think, that I'd like to point out.

> The idea is that some future implementation might somehow put the object
> into ROM despite it being allocated dynamically, and that it might then be
> undefined to cast const away (as for static objects).

Here it is. Do you speak about ROM in technological sense (Read-Only Memory
that can be erased only by using special electrical/ultraviolet means)?
A much more often encountered case is making the memory read-only through
software by using page protection on architectures with MMU. You reset the
write bit for a page, and if someone later writes in it, you'll have an
interrupt.
Please note that many compilers do it today - they have a const data section
where they put const POD objects.
It's easy to conceive a const heap allocator that unprotects memory prior to
do a construction/destruction and protects it again when that process ends.

Consequently, I tend not to agree with the following:

>the very notion of
> deleting ROM is bizarre.

I think it's not if you think ROM as being obtained through page protection.

> I also think it is reasonable to use a garbage collector with C++. Look at
> it this way: any implementation clever enough to make heap-allocated
> objects read-only on the fly should also be clever enough to deallocate
> them automatically.

It's much easier to make read-only objects on the fly than a garbage
allocator.

I agree that the existence of a genuinely const heap seriously shatters the
arguments of the anti-standard participants to this discussion. Someone
qouted from the standard that "calling the new operator on a cv-qualified
type returns a pointer to a cv-qualified type", which at least leaves room
for implementing a const heap.
On the other hand, delete-ing const object has several disdvantages, which
leads to quite an unpleasant stae of affairs.

So from now on, whenever someone brings up an argument against the standard
in this issue, a solution to the const heap issue should be brought up as
well.

IMHO, I would like to see a solution that would strengthen the consistency
of const. As we all know, const is an awesome design tool in C++. Having
better const-guarantees leads ultimately to better C++ programs.

Andrei
---
[ 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/04/13
Raw View
Dave Harris wrote:
>
> celtschk@physik.tu-muenchen.de (Christopher Eltschka) wrote:
> > [...] but this time the object itself is const.
>
> See elsewhere in this thread for arguments that there is not truly a const
> heap. If they are correct, then casting away const would always be safe.

Standard quote, from another posting in this thread:

 | 5.3.4 - New [expr.new]
 ...
 | [Note: the
 | type-id may be a cv-qualified type, in which case the object created
 | by the new-expression has a cv-qualified type. ]

Note that this says the *object* has a cv-qualified type, not just
the pointer returned.
Now while notes are not normative, I'd be _very_ surprised if this
note contradicted the normative text.

>
> > BTW, one could consider the constructor not honoring const a hole
> > as well, since you can write:
>
> No; X::myself is an alias. You can circumvent const by using a non-const
> alias, of course. That your example makes the alias an instance variable
> is not relevant; it could equally well be static.

Note that this generates - without a const_cast - a non-const
pointer to a const object (and since this is true even for static
objects, you cannot make your "no const in heap" argument at all
in this case).

Yes, it is an alias. But it's a non-const access path to a
const object, without any cast. Therefore it can be considered
a const hole. It's not at all equivalent to a non-const pointer
to a non-const object, used from inside a const method (of from
a function with only a const object).
Note that only the constructor and destructor have a non-const
pointer to a const object. There's no other way to obtain such
an access path without a cast. OTOH, it (certainly) is easy to
get a non-const access path to a non-const object.
---
[ 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: sirwillard@my-dejanews.com
Date: 1999/04/08
Raw View
In article <memo.19990402092915.51951C@btinternet.com>,
  brangdon@cix.co.uk wrote:
> sirwillard@my-dejanews.com () wrote:
> > delete doesn't change an object.  It just ends it's lifetime.  Lifetime
> > is not a property of an object.
>
> Surely it is. What else is it a property of?

Well now, that depends on what you mean by "property". To me, a property of
an object is only that that is part of the object's interface. The lifetime
is obviously not a property of the object by this view point.

> > It makes sense, because if you couldn't delete a const pointer you'd be
> > unable to free such memory _EVER_.
>
> You could delete it through some other non-const reference (or through a
> const-cast, which we'll ignore). Consider:
>
>     void func() {
>         Object temp;
>         const Object &myObject( temp );
>         //...
>         // temp destroyed at end of scope.
>     }
>
> Or:
>
>     void func() {
>         Object *temp = new Object;
>         const Object &*myObject( temp );
>         //...
>         delete temp;
>     }

So, you want to enforce dangling pointers instead of memory leaks.  Not to
mention the extra coding of what is in essence a hack to work around a poorly
defined definition of const.  This concept is ugly and counter to the behavior
exhibited by stack based objects.  Take the following for an example:

void func() {
   const Object obj;
}

Now we have a const pointer (the "this" pointer) and storage that is "const".
Following your semantics, "const" applies to lifetime, so obj can't be
destroyed.  If you change the semantics to deal with stack based objects
differently from heap based ones than you've left things in a very muddled
state.  This just isn't logical.

> You appreciate that a "const" reference does not mean the object cannot be
> changed; it means the object cannot be changed through that reference.

I understand this, but are you trying to say that this is more intuitive?  I
fully understand why this rule exists (why it MUST exist) but I would think
newbies would be more confused by this than by the fact you can delete a const
object.  I've seen many people try and give alternative syntax or patterns for
deleting const objects under a ruling that const also applies to lifetime, and
every single one of these attempts leads to code that is MUCH less intuitive
(or even just plain non-understandable) to the current semantics.  Therefore,
the argument about intuitiveness is a non-argument, as far as I'm concerned.

> > Great way for the language to force memory leaks onto you, no?
>
> That needn't follow. For auto and static objects the compiler would still
> be free to delete the object behind the scenes, roughly as if it had
> translated into the above "non-const temporary" model.

Such "behind the scenes" semantic rules lead to the overall semantics being
LESS intuitive.  You add a lot of complexity for, IMHO, no gain.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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" <andreia@netzip.com>
Date: 1999/04/08
Raw View
John D. Hickin <hickin@hydro.cam.org> wrote in message
news:370B52D4.4FF7@pop.hip.cam.org...
> I argue that destruction is logically const because no observation that
> you may undertake afterwards can detect a change of state.

Crashing the program is quite observable to me.

Andrei
---
[ 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" <andreia@netzip.com>
Date: 1999/04/08
Raw View
Andrew Koenig <ark@research.att.com> wrote in message
news:F9vFp0.JxK@research.att.com...

Andrew,

Now I can continue via the newsgroup - youpeee!

> I completely agree.  But in the committee discussion, it came out that
> there were some programs that were entirely plausable that one might
> like to write, and there was no way to write them otherwise.

I maintain there are several ways around it. The most general problem is:
I'm in a template, I have a type T, and I want to obtain the type 'non_const
T'. This is doable in a number of ways. I posted some code around the delete
problem you told aboyt. Please let me outline the most general mechanism:

template <typename T>
struct type_traits
{
    typedef T non_const;
    typedef T & reference;
    typedef T & non_const_reference;
    // other typedefs..
};

template <typename T>
struct type_traits<const T>
{
    typedef T non_const;
    typedef const T & reference;
    typedef T & non_const_reference;
    // other typedefs..
};

Now whenever you want a non-const version for a T, you use
type_traits<T>::non_const. I mean:

template<class T> void proc(args) {
typename type_traits<T>::non_const * tp = new T;
// ...
delete tp;
}

In particular, the type_traits approach solves the 'reference-to-reference'
problem. This problem appears with bind1st and bind2nd (see the recent
thread). The solution is to specialize type_traits like this:

template <typename T>
struct type_traits<T &>
{
    typedef T & reference;
    typedef T & non_const_reference;
    // other typedefs..
};

template <typename T>
struct type_traits<const T &>
{
    typedef const T & reference;
    typedef T & non_const_reference;
    // other typedefs..
};

So the argument that "it's impossible" can be at most "is not simple
enough". Please note that there are other problems that type_traits solve. I
am actually using them for other purposes.

>That
> argument seemed to be stronger--especially when expressed in the form
> ``If I allocated it, I should be able to deallocate it.''  Such a
> guarantee is extremely important, for example, if you are writing
> a library container class.

type_traits.

Let's recap.
Things that seemed impossible are doable.
Things that shouldn't happen at all -- plain bugs -- compile cast free,
trick free, flag free. Fat free if you want :o).
Simple rules go into complicated rules. I mean: "A function taking a pointer
to a const object will normally leave the object in the same state, except
for the case when in calls delete against the pointer, case in which you get
a cadaver back, with which you cannot do anything of any interest".
(I am speaking in the absence of casts. Casts can destroy any design
whatsoever.)
The killer argument is not that lethal and does not convince people quite a
lot. There have been reasonable points raised about it.
The 'genuine const object on the heap' does not exist. All objects on the
heap can safely have the const casted away.
To my sadness, I saw true computer professionals getting hysterical, others
making illogical points, and others making childish mistakes.

With no intention to offend anyone, please allow me to quote from Winston
Churchill: "I would rather be right than consistent".

Andrei
---
[ 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: "Niklas Borson" <a-niklab@microsoft.com>
Date: 1999/04/08
Raw View
Dave Harris <scorp@btinternet.com> wrote in message
news:memo.19990406134512.27141A@btinternet.com...
> [...]
> Consider a function whose prototype is:
>
>     void proc( const Object *pObject );
>
> Should this function be allowed to delete its argument? This is the key
> question.
>
> I think it shouldn't. For me this is so obvious that I have trouble
> explaining it. It's what const is *for*. The declaration of the function
> is saying that (aliases aside) it has no logical effect on its argument.
> Destruction is a major effect.
> [...]

It is possible to declare the function differently, such that it
guarantees to neither change nor delete the object:

    void proc( const Object& object );

As to meaning of const... I think if an object is const it means
you can't change its logical state. The question then is: Does
deleting an object change its state? "Of course it does!" you might
say, and common sense would tend to support your position. But
there are sound philosophical reasons for distinguishing between
an object's lifetime (existence) and state (attributes).

For example, Kant refuted the ontological proof of the existence
of God by showing that existence is not a predicate. (The proof
goes something like: God is perfect by definition; an existing
thing is more perfect than a non-existing thing; therefore God
exists necessarily.) Kant said existence is not an attribute of
a thing, therefore you can't prove a thing's existence based on
its definition.

If you accept this distinction, then I don't think it's counter-
intuitive to say that "const" makes an object's state read-only
but does not guarantee its lifetime.

Of course the difficulties of managing object lifetimes are real,
but they have more to do with the use of pointers than with const.
---
[ 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: "John D. Hickin" <hickin@Hydro.CAM.ORG>
Date: 1999/04/08
Raw View
Andrei Alexandrescu wrote:
>
> John D. Hickin <hickin@hydro.cam.org> wrote in message
> news:370B52D4.4FF7@pop.hip.cam.org...
> > I argue that destruction is logically const because no observation that
> > you may undertake afterwards can detect a change of state.
>
> Crashing the program is quite observable to me.
>

Permit me a clarification: _observation with defined program results_; I
don't want to crash and I really don't want my hard drive formatted
either :-). I also meant observable from within the program, not
externally (i.e., outside the system) which is an entirely different
thing, although I thought that I was being perfectly clear.

The only way to deal with this situation is to abandon references and
pointers in favour of universally unique object identifiers and some
sort of object repository. Now you can more reliably detect when an
object disappears; at least you won't crash.


Regards, John.
---
[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/08
Raw View
Biju Thomas <b_thomas@ibm.net> writes:

>Nathan Myers wrote:
>>
>> J.Barfurth<techview@bfk-net.de> wrote:
>> >Nathan Myers schrieb in Nachricht <7edokk$mgo$1@shell7.ba.best.com>...
>> >>There is no such thing as a const object on the heap.
>> >
>> >Does this mean, that 'new' actually ignores top-level constness ? Like:
>> >    const T* p = new const T();          // *p is _actually_ non-const
>> >    const_cast<T*>(p)->change();    // results are well-defined
>>
>> Yes.  There is no operator const_new().  Operator new() returns
>> a non-const pointer which is passed to the constructor.
>
>I think we are talking about new expression here, not operator new. A
>note in 5.3.4 para 1 of the standard says:
>
>====
>the type-id [in the syntax for the new-expression] may be a cv-qualified
>type, in which case the object created by the new-expression has a
>cv-qualifid type.
>====
>
>Doesn't this mean that there can be const (and volatile) objects on the
>heap?

Yes, it does.  However, unfortunately 3.8 "Object Lifetime [basic.life]"
paragraph 9

 |  -9- Creating a new object at the storage location that a const object
 |  with static or automatic storage duration occupies or, at the storage
 |  location that such a const object used to occupy before its lifetime
 |  ended results in undefined behavior.

restricts itself to objects with static or automatic storage duration.
This makes it difficult for an implementation to actually write-protect
objects on the heap.

If this paragraph included objects with dynamic storage duration,
then the implementation would have more freedom to write-protect things.
For example, if the compiler sees

 const Object *p;

 int main() {
  p = new const Object("blah");
  ...
 }

and the implementation detects that the program has not overriden
the global operator new or delete, then the compiler could inline
the constructor for `Object', execute it at compile time, and place
the resulting value in ROM.  (Of course for this to work the global
operator delete should handle deallocations of such values appropriately,
e.g. by ignoring any attempts to deallocate memory in ROM.)

As a more useful example, debugging implementations (like Purify,
ObjectCenter, etc.) could dynamically write-protect memory whenever
the constructor for a const object finished executed, and dynamically
disable that write-protection whenever the destructor started executing.
This could apply to all memory areas -- static memory, stack and heap.

However, with 3.8 paragraph 9 restricted as it is, it is pretty hard
for an implementation to write-protect memory on the heap.  I think
this is what Nathan meant when he said "There is no such thing as a
const object on the heap".  A user is free to write code such as

 new (p) const Object("something else");

or even to reuse the storage for some entirely different type

 new (p) int(42);

and in both cases the user does not need to delete the old const object
first, and does not need to call its destructor first either.

I don't know what the rationale for including the words
"with static or automatic storage duration" in 3.9 paragraph 9 was.
Perhaps someone could explain it to me.

>Regarding operator new returning a pointer to some const (ie, read-only)
>pointer, wouldn't it be possible to write a class specific allocator,
>which may return a pointer to some read-only storage?

I think not, but the standard is not entirely clear about this.

It is pretty clear that for array new, the intent was to allow
implementations to allocate additional memory and store a count
of the number of objects allocated (or their size) into the additional
memory allocated.  Obviously this wouldn't work if the storage was
read-only.

In 3.7.3.1 "Allocation functions [basic.stc.dynamic.allocation]"
the standard says "The pointer returned shall be suitably aligned so that
it can be converted to a pointer of any complete object type and then used
to access the object or array in the storage allocated".
But what does "access" mean?  Does it mean "read" or does it mean
"read or write"?  Is there a difference between "access the object"
(which is used here) and "access the stored value of an object"
(which is used elsewhere)?

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ 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@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/04/10
Raw View
On 08 Apr 99 12:02:25 GMT, J.Barfurth <techview@bfk-net.de> wrote:
>Siemel Naran schrieb in Nachricht ...

>A delete-statement invokes two actions: calling a destructor and invoking
>the appropriate operator delete.

Right.


>3) There is no problem with calling the destructor for a const
>object(although this in turn might invoke additional non-const behaviour).

Right.  Because this is ok:
   int main() { const T t; }
this should be ok too:
   int main() { const T * t=new T(); t->~T(); } // note: memory leak!

But if you proposed to make implicit calls of a destructor of a const
object ok but explicit calls ill-formed, that would be even better.
   int main() { const T t; } // ok
   int main() { const T t; t.~T(); } // error
   int main() { const T * t; t->~T(); } // error


>4) OTOH, operator delete should be invoked only for a non-const pointer.

Right.


>Although I'm not yet convinced that I want to follow this argument all the
>way, it gives this discussion an interesting twist:

>- No more breaking analogies or unexplained asymmetries.

Ok.

>- The difference between { T const* p = new T(); delete p; } and { T const
>t; } is moved to where it obviously exists: memory (de-)allocation.

Ok.  But if you wanted the explicit call of a destructor to be illegal
too, that would be ok with me!  Sure, it's somewhat illogical, but it
does make C++ safer.

>- None of the arguments so far addressed the issue of POD vs. non-POD types.
>(IIRC the original post was about deleting a int const*, which needn't be
>affected by discussion of mutating destructors). I discovered this potential
>problem only this morning and now it's gone already :-).

Good point.  From this point of view, explicit calls of any destructors
should always be legal.  It would be ridiculous to special case: builtin
destructors are ok to call, but user type destructors are not ok to call.
We have this annoying duality for builtin operators and user operators;
the former have sequence points, the latter do not.  But, once again,
I'm in favor of these somewhat illogical rules because they make C++ a
little safer:
   void f(T const * t) {
      t->~T(); // error: can't explicitly call dtor on const object
      ::operator delete(t); // error: can't deallocate memory to const object
   }

--
----------------------------------
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: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/04/10
Raw View
On 08 Apr 99 13:06:40 GMT, Matt Austern <austern@sgi.com> wrote:

>What Andy's example does mean, though, is that you can't forbid
>    "delete x"
>by making general rule about about destructors and const objects.
>Forbidding it would require a special-case rule dealing with the
>specific syntactic construct of a delete-expression.  We would then
>have to worry, on a case-by-case basis, about other syntactic
>constructs that can result in a destructor getting invoked.

No, my rule is simple.  In the statement "delete x", 'x' must be
a pointer to non-const.  End of story.

--
----------------------------------
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: "Andrei Alexandrescu" <andreia@netzip.com>
Date: 1999/04/10
Raw View
Dave Harris <scorp@btinternet.com> wrote in message
news:memo.19990407023805.5569E@btinternet.com...
>
> ark@research.att.com (Andrew Koenig) wrote:
> > But there is no such guarantee anyway, even if the type system is
> > completely strict about const, because f might have a non-const alias
> > to p that it obtained from another source.
>
> But that is true for all const operations, not just operator delete(). You
> seem to be arguing that const has no value at all. Or perhaps you are just
> nit-picking?

I agree with Dave. By bringing such arguments, you can render pretty much
damn all useless. Think of casts for instance.

> It seems clear to me that const does have value as part of an interface
> declaration, and that value is diminished by allowing const objects to be
> deleted.

It seems clear to me, too.
I think Andrew thinks the same, but he understandably cares about the
template example he's given.

Andrei
---
[ 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: "Matt Seitz" <mseitz@meridian-data.com>
Date: 1999/04/10
Raw View
One of the things that impressed me when reading THE DESIGN AND EVOLUTION OF
C++ was how often decisions were made based on real world experience with
large projects and with other programming languages.  So far, we've had lots
of theoretical arguments, analogies, and small examples.  I would be
interested in hearing about actual experiences on large projects.  Have
there been large projects that had problems under the old rule (delete
prohibited) or were significantly enhanced by the new rule?  Are there any
large projects that have been seriously hurt by the new rule?

How about the experience of other languages?  For example, I believe the
following is not legal in C:

T const * p =malloc(sizeof(T));
free(p);

Has this been a burden to C programmers?  Has this issue been addressed in
other languages?

"There seem to 'good arguments' for every possible language feature and
every possible use of it.  What we need is data.  Without data and properly
evaluated experience, we are like the Greek philosophers who argued
brilliantly for several centuries, yet didn't quite manage to determine the
four (or maybe even five) fundamental substances from which they were sure
everything in the universe was composed."
--Dr. Bjarne Stroustrup, THE DESIGN AND EVOLUTION OF C++ (Section 13.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/04/10
Raw View
Andrew Koenig<ark@research.att.com> wrote:
>Dave Harris <brangdon@cix.co.uk> wrote:
>
>> The main motivation for allowing it seems to be cases like:
>>     void proc() { const Object *pObject = new Object; delete pObject; }
>> where we are imitating auto scope.
>
>That argument is not particularly important in that particular form.
>The form that is important is
> template<class T> void proc(args) { T *tp = new T; delete tp; }
>Now, you don't know whether T is a const type.  If you could not say
>"delete tp;" directly, there is no cast you could write that would allow
>it.

NB This argument has already been neatly disposed of.  A helper
template, or for full generality a traits class template, does
the job.

BTW, my use of the term "fraudulent" has raised tempers, and I
apologize.  The usage was an allusion to a remark by bs in D&E:
"argument by analogy is fraud".  Probably that expression should
be limited to referring to one's own straw 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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/04/10
Raw View
Biju Thomas <b_thomas@ibm.net> wrote:
>Nathan Myers wrote:
>> J.Barfurth<techview@bfk-net.de> wrote:
>> >Nathan Myers schrieb in Nachricht <7edokk$mgo$1@shell7.ba.best.com>...
>> >>There is no such thing as a const object on the heap.
>> >Does this mean, that 'new' actually ignores top-level constness ?
>> Yes.  There is no operator const_new().  Operator new() returns
>> a non-const pointer which is passed to the constructor.
>
>I think we are talking about new expression here, not operator new. A
>note in 5.3.4 para 1 of the standard says:
>
>====
>the type-id [in the syntax for the new-expression] may be a cv-qualified
>type, in which case the object created by the new-expression has a
>cv-qualifid type.
>====

Fergus has already dealt with this. (Thanks, Fergus.)
I will only add that the second half of the above was
added _after_ the ARM rule was changed, so it begs the
question.

--
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/04/10
Raw View
sirwillard@my-dejanews.com () wrote:
> Well now, that depends on what you mean by "property". To me, a
> property of an object is only that that is part of the object's
> interface.

Oh, OK; I wasn't expecting that restricted sense.


> Not to mention the extra coding of what is in essence a hack to
> work around a poorly defined definition of const.  This concept is ugly
> [...]

Well, that is a value judgement. There is extra coding, true, but
achieving const correctness often requires extra coding. Consider methods
like std::vector<>::begin(), which has to be defined twice, once const and
once non-const. This is the same.

If you don't like the extra work a static type system puts you to, you
should consider switching to some other language, like Smalltalk. There is
no free lunch here.

(See the rest of the thread for the various other points. For example, how
use of a wrapper template class would avoid a second pointer.)

  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/04/11
Raw View
Andrew Koenig<ark@research.att.com> wrote:
>There are really two attributes that we are trying to lump together:
>One is whether it should be permitted to modify an object; the other
>is whether it should be permitted to delete an object.

Yes, that was the original issue, although teasing those apart is what
got people confused in the first place.  They are easy to separate
syntactically.  The issue is semantic, though.

It is conventional to "lump together" attributes and give the aggregate
a name.  Const is a name for a wide variety of language behaviors.
(Count uses of it in the normative text.)  The question is, does
it name anything meaningful?  Given the new rule, that is a lot harder
to answer affirmatively.

>So the question is how this attribute
>should be expressed within the C++ type system.  There seem to be
>two alternatives:
>
> 1. Link it to const.
> 2. Don't express it in the type system.
>
>Both these alternatives have advantages and disadvantages, and opinion has
>always been divided about which one is better.  I personally favor (2),
>but many people whom I personally respect favor (1).  Realizing that there
>is really another attribute here has convinced me that this debate cannot
>be definitively settled within the language as it exists today.

The advantages of linking it to const have been acknowledged.
So far nobody has presented any disadvantages that withstood
scrutiny.  (Thank you, Andrei, for the most detailed scrutiny.)
The only inconvenience discovered was the need for a const_cast<>
to inform the compiler that you were violating constness, which
is what const_cast<> is for.

The real issue is, what is const for?  It should provide the strongest
possible guarantees about the sanctity of the object it protects, so
that we need not fear releasing a T const* pointer to the world-at-large.
Otherwise it's hard to say what it _is_ good for.

For those who like analogies, consider improving the Unix file system
by analogy with the new C++ rule.  _Now_ you may truncate any file to
which you have read-only access.  Could we consider allowing read
access to /etc/crontab?  No, we would need to provide a separate,
trusted program which has read access, and dumps the contents to
stdout.  Would this be an improvement?  Would there be any point to
having a "read" bit in the inode at all, then?

In Standard C++, where we have made the analogous change, the best
I can do now is release references rather than pointers.  References
cannot be used in many places where I use pointers.  I could make
smart pointers, but they are not usable everywhere (e.g. STL).
Instead, I must pretend that the old rule obtains, and rely on clients'
"good style".

I would like to see compiler warnings:

  warning: deletion via pointer-to-const.
  warning: explicit destructor call via [pointer|reference]-to-const.

Then at least the better compilers could add some safety.  It's a pity
that the language was weakened so that both can only be warnings,
rather than strengthened so that they would both be errors.

--
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/04/11
Raw View
ark@research.att.com (Andrew Koenig) wrote:
>  A const member of a non-const dynamically object
>  can be deleted, but not modified.

I don't agree. To me it satisfies the insightful criteria you just gave:

> (it can be destroyed, but you can't use its address as an
> operand of delete)

For example:
    class Object {
    public:
        const int x;
        const int y;
    };
    Object *p = new Object;
    delete p;   // OK!

Here "p->y" is being destroyed, but we did not call "delete &p->y;".
Likewise with "p->x" (let's not get into whether "&p->x" has the same
value as 'p'.)

This is crucial. In my view, only objects which can be modified are
suitable arguments for operator delete(). This means that "dynamic" and
"const" are not independent after all - "const" objects cannot be
"dynamic". We *could* introduce a new property, and maybe it would be
useful (if we could express the concept, "You can write to this object but
not delete it"). We can also manage without it.

  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/04/11
Raw View
celtschk@physik.tu-muenchen.de (Christopher Eltschka) wrote:
> [...] but this time the object itself is const.

See elsewhere in this thread for arguments that there is not truly a const
heap. If they are correct, then casting away const would always be safe.


> BTW, one could consider the constructor not honoring const a hole
> as well, since you can write:

No; X::myself is an alias. You can circumvent const by using a non-const
alias, of course. That your example makes the alias an instance variable
is not relevant; it could equally well be static.

  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: "AllanW {formerly AllanW@my-dejanews.com}" <allan_w@my-dejanews.com>
Date: 1999/04/11
Raw View
In article <7eaq69$ll$1@nnrp1.dejanews.com>,
  Jim Hyslop <jim.hyslop@leitch.com> wrote:
> The point in question is, are you allowed to delete a const pointer?  Certain
> compilers will not let you do this:
> void f()
> {
>    const T *t=new T; // assume T is defined
>    //...
>    delete t;
> }
>
> because these compilers are (incorrectly) looking at it from the point of
> view of "Deleting a const object is an attempt to modify it."  Well, from
> that point of view, then *creating* a const object (or, shall we say, an
> object that will be const) should also be disallowed because you are
> attempting to modify a constant object.  Therefore, by this reasoning, you
> can neither create nor destroy a constant object - which is clearly not the
> intent of 'const'.

The code fragment above doesn't use new to create a const T. It uses new
to create a T, and then copies the address to a const T pointer. The
analogy of creating a const object would be something like:

    const T *t = new const T;

which, as far as I know, *is* legal -- and the "const-ness" doesn't
apply until the constructor is complete.

----
Allan_W@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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/04/11
Raw View
Matt Seitz wrote in message <370ce63d.0@newsread.exodus.net>...
>One of the things that impressed me when reading THE DESIGN AND EVOLUTION
OF
>C++ was how often decisions were made based on real world experience with
>large projects and with other programming languages.  So far, we've had
lots
>of theoretical arguments, analogies, and small examples.  I would be
>interested in hearing about actual experiences on large projects.  Have
>there been large projects that had problems under the old rule (delete
>prohibited) or were significantly enhanced by the new rule?  Are there any
>large projects that have been seriously hurt by the new rule?
>

This issue is not the only one where the committee decided to innovate or
modify based on what they opined ought to be good language rather than on
extensive usage of a particular feature or behavior. This is one of the
costs of the new accelerated model of today for language standardization
wherein intuition and assumption rather than experience and emperically
gained wisdom can be a criteria for langage specification. By choosing to
innovate language rather than codify existing practice, the committee
incurred this cost. In most cases their choices were at best correct and at
worst harmless. Which is this? This debate and the credibility of the
opposing participants and the merits of their arguments leave that question
unanswered for those who are as yet undecided.
---
[ 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: paulp.removethis@ccnet.com (Paul)
Date: 1999/04/01
Raw View
   >Deleting a const pointer is ok (that's just common
   >sense anyway).

The standard explicitly allows for deleting a const pointer.
See section 5.3.5.2. However, I'm not sure it's "common
sense," though. Since operator delete() invokes the destructor
of an object and the destructor is not a const function,
data can very well be modified.

Paul
---
[ 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/04/01
Raw View
Dave Harris wrote:
>
> Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > Deleting a const pointer is ok (that's just common
> > sens anyway).
>
> I agree the standard says it is OK. I don't see that it is common sense.
> The destructor changes the state of the object, can and probably does
> overwrite its bytes with garbage etc. In what way is it a const operation?
>
>   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."

'const' inhibits operations that change the value of the object; it has
no relevance to operations that cause the object to cease to exist. If
it did, then logically it should also prohibit operations that bring
them into existence.
---
[ 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: sirwillard@my-dejanews.com
Date: 1999/04/01
Raw View
In article <memo.19990331153152.27063C@btinternet.com>,
  brangdon@cix.co.uk wrote:
>
> Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > Deleting a const pointer is ok (that's just common
> > sens anyway).
>
> I agree the standard says it is OK. I don't see that it is common sense.
> The destructor changes the state of the object, can and probably does
> overwrite its bytes with garbage etc. In what way is it a const operation?

delete doesn't change an object.  It just ends it's lifetime.  Lifetime is not
a property of an object.

It makes sense, because if you couldn't delete a const pointer you'd be unable
to free such memory _EVER_.  Great way for the language to force memory leaks
onto you, no?

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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: Biju Thomas <b_thomas@ibm.net>
Date: 1999/04/01
Raw View
Dave Harris wrote:
>
> Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > Deleting a const pointer is ok (that's just common
> > sens anyway).
>
> I agree the standard says it is OK. I don't see that it is common sense.
> The destructor changes the state of the object, can and probably does
> overwrite its bytes with garbage etc. In what way is it a const operation?
>

We are talking about state of the object, not the state of raw bytes.
There is no state for a destructed object. So, there is no meaning in
talking about state changes in a destructor.

Ok, that was just an argument :-)

But, deleting const objects is useful, I think.

For example, suppose I have a factory object (XFactory) which creates
both const and non-const 'X' objects. I don't want some clients to have
access to non-const X objects, because, I don't want them to write to
some secure database/file/hardware.

class XFactory {
public:
  X* create ();
  const X* create () const;
private:
  XFactory ();
};


The clients will be given pre-built XFactory object, some will get const
XFactory, and, some will get non-const XFactory.

eg:

void f ( const XFactory& aFactory )
{
  const X* aX = aFactory.create();
  // do something
  delete aX;
}

If deleting through const pointer was disallowed, this would not have
been possible.

Best regards,
Biju Thomas
---
[ 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: "Matt Seitz" <mseitz@meridian-data.com>
Date: 1999/04/01
Raw View
Dave Harris wrote in message ...
>
>Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
>> Deleting a const pointer is ok (that's just common
>> sens anyway).
>
>I agree the standard says it is OK. I don't see that it is common sense.
>The destructor changes the state of the object, can and probably does
>overwrite its bytes with garbage etc. In what way is it a const operation?

I can understand the confusion cause by allowing a const object to be
modified.  However, it is consistent with how const objects are treated in
general.  Calling a destructor is the one non-const operation that can be
called on const object.  Likewise, delete is the one non-const operation
that can be called on a pointer to a const object.

Consider the basic case of an automatic object

void foo(){
    TObject const object;
    //function body

} //call destructor on object

Despite object being "const", the destructor is called and can modify the
object.  The alternatives would be either to not call the destructor for a
const object, making it impossible for a const object to release its
resources, or to prohibit const objects.

Keep in mind that const does not mean "does not change the object."  It
means "does not change the object in any way that can be detected by a user
of the object."  Since the object is now out of scope and undefined, there
should no longer be any users of object.

Deleteing a const pointer is just the dynamic equivalent:

void foo(){
    TObject const * pObject = new Object;
    //function body

    delete pObject;
}
---
[ 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: "John D. Hickin" <hickin@hydro.cam.org>
Date: 1999/04/01
Raw View
Dave Harris wrote:
>
> Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > Deleting a const pointer is ok (that's just common
> > sens anyway).
>
> I agree the standard says it is OK. I don't see that it is common sense.
> The destructor changes the state of the object, can and probably does
> overwrite its bytes with garbage etc. In what way is it a const operation?
>

I fear that no matter what rule is adopted (old compilers like cfront
disallow the delete) something must be somewhat broken. Consider the
following:

void f1() {
  const X x;
  ...
  // ~X runs here
};

void f2() {
  const X* pX = new X;
  ...
  delete pX; // ~X runs here
}

Are the two not equivalent under the current rules? Under the old rules,
f2 would not compile. But surely the destruction undertaken in f1 isn't
const either.
---
[ 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 <dtribble@technologist.com>
Date: 1999/04/01
Raw View
Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
>>> Deleting a const pointer is ok (that's just common
>>> sense anyway).

Dave Harris wrote:
>> I agree the standard says it is OK. I don't see that it is common
>> sense.  The destructor changes the state of the object, can and
>> probably does overwrite its bytes with garbage etc. In what way is
>> it a const operation?

James Kuyper wrote:
> 'const' inhibits operations that change the value of the object; it
> has no relevance to operations that cause the object to cease to
> exist. If it did, then logically it should also prohibit operations
> that bring them into existence.

There's also the viewpoint that the owner of an object is the one
that created it, and thus it should be allowed to destroy it
as well.  Specifically, a class "owns" its members, some of which
may be pointers to const objects.  The member functions of the
class thus should not only be allowed to control the creation
of these objects, but also the destruction of them.  If we don't
want the class member functions to modify the contents of these
objects once they are created and initialized, then it makes sense
to declare them as const objects.

Here's a concrete example:

    class NamedItem
    {
    public:
        bool    open(const char *name);
        void    close();
        ...

    private:
        const char *    m_name;     // Saved name
    };

    bool NamedItem::open(const char *name)
    {
        // Save a copy of the name
        char *  n;
        n = new char[std::strlen(name)+1];  // [A]
        std::strcpy(n, name);
        m_name = n;                         // [A2]
        ...
    }

    void NamedItem::close()
    {
        // Deallocate the saved name
        delete m_name;              // [B]
        m_name = NULL;
        ...
    }

    ...

In this class, we have an open() function that saves a copy of
its 'name' argument by allocating a char array object and
initializing its contents by copying the name into it (at [A]).
Since I don't intend any of the other member functions to modify
the contents of the saved string, I declare it const.  (This also
lets the compiler issue errors if any of my member functions do
in fact try to modify the contents of m_name.)  Once I'm past
point [A2], no other functions should modify the string.

The close() function throws away the saved string by deleting it
(at [B]).  Common sense dictates that I should be able to do this
with a simple 'delete m_name' expression, regardless of whether the
object is const or not.  I'm not modifying the string, I'm simply
discontinuing its existence as an allocated object.  Setting
m_name to null confirms the fact that there no longer exists an
object to point to.  But nowhere during the lifetime of the string
object did I modify its contents, which is why it makes sense to
declare it const.

-- David R. Tribble, dtribble@technologist.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: Jochen Klein <Jochen.Klein@gmx.de>
Date: 1999/04/01
Raw View
sirwillard@my-dejanews.com wrote:
>
> In article <memo.19990331153152.27063C@btinternet.com>,
>   brangdon@cix.co.uk wrote:
> >
> > Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > > Deleting a const pointer is ok (that's just common
> > > sens anyway).
> >
> > I agree the standard says it is OK. I don't see that it is common sense.
> > The destructor changes the state of the object, can and probably does
> > overwrite its bytes with garbage etc. In what way is it a const operation?
>
> delete doesn't change an object.  It just ends it's lifetime.  Lifetime is not
> a property of an object.
>
> It makes sense, because if you couldn't delete a const pointer you'd be unable
> to free such memory _EVER_.  Great way for the language to force memory leaks
> onto you, no?

Sorry, but constness is a property of the pointer to the object, not of
the object itself! So there is no problem to delete the object through
some other, non const pointer. If there is none? Well, nothing prevents
you from giving up all pointers to an object without deleting it.

please note: I think it's good, that you can delete through a count
pointer.

Jochen


[ 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: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/04/01
Raw View
In article <3703AFD8.FFA7F7E8@gmx.de>,
Jochen Klein  <Jochen.Klein@gmx.de> wrote:
>Sorry, but constness is a property of the pointer to the object, not of
>the object itself!

That may be what the Subject line says, but read what he wrote in the
message, which was of the form:

const T * p = new T;

That's a mutable pointer to a const object.  A const pointer would be:

T * const p = new T;

--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ 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/04/02
Raw View
mseitz@meridian-data.com (Matt Seitz) wrote:
> Keep in mind that const does not mean "does not change the object."  It
> means "does not change the object in any way that can be detected by a
> user of the object."  Since the object is now out of scope and
> undefined, there should no longer be any users of object.

I think that having the object deleted implicitly by the system as it goes
out of scope, rather than explicitly by the programmer through a public
API, makes a conceptual difference. So yes, it makes sense to allow that
case. One could think of the compiler has having a hidden. non-const
reference to the object.


> Deleteing a const pointer is just the dynamic equivalent:

But it's not conceptually equivalent! I can see that people writing that
kind of code would like the convenience, but that is not a logical
argument. A wrapper class would give the same kind of convenience, so that
is not a compelling issue either.

I'm not expecting a language change now; I'm just registering surprise
that people think this behaviour is "common sense".

  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: James Kuyper <kuyper@wizard.net>
Date: 1999/04/02
Raw View
Barry Margolin wrote:
....
> const T * p = new T;
>
> That's a mutable pointer to a const object.  A const pointer would be:

'mutable' is a C++ keyword with a different meaning than non-const; I
recommend not using it as a antonym for 'const'.
---
[ 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/04/02
Raw View
kuyper@wizard.net (James Kuyper) wrote:
> 'const' inhibits operations that change the value of the object; it has
> no relevance to operations that cause the object to cease to exist. If
> it did, then logically it should also prohibit operations that bring
> them into existence.

I don't see how that follows. How can something that doesn't exist be
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: source@netcom.com (David Harmon)
Date: 1999/04/02
Raw View
On 31 Mar 1999 16:40:53 GMT in comp.std.c++, scorp@btinternet.com (Dave
Harris) wrote:
>I agree the standard says it is OK. I don't see that it is common sense.
>The destructor changes the state of the object, can and probably does
>overwrite its bytes with garbage etc. In what way is it a const operation?

I don't know any reason for a destructor to change the state of a const
object.  The object is going to disappear next; its state no longer
matters and need not be anything in particular.  The destructor's job
is other things, like releasing resources the object is using.

Still, maybe we need:

   class foo {
   public:
       ~foo();
       ~foo() const;
   ...
---
[ 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/04/02
Raw View
Dave Harris wrote:
>
> kuyper@wizard.net (James Kuyper) wrote:
> > 'const' inhibits operations that change the value of the object; it has
> > no relevance to operations that cause the object to cease to exist. If
> > it did, then logically it should also prohibit operations that bring
> > them into existence.
>
> I don't see how that follows. How can something that doesn't exist be
> const?

It can't, which is the point. Being 'const' is a matter of the
difference between the initial and final states of an object. At the
start of construction, and at the end of destruction, there is no
object, so there is no issue of const-ness. If you believe that the
transition from existence to non-existence should be considered a
violoation of const-ness, then so must the reverse transition. That's
not how the standard is written, for good reasons.


[ 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: "Matt Seitz" <mseitz@meridian-data.com>
Date: 1999/04/02
Raw View
Dave Harris wrote in message ...
>I'm not expecting a language change now; I'm just registering surprise
>that people think this behaviour is "common sense".

I see your point that a reasonable person might expect that by declaring a
pointer to a const object that one could not delete the object using that
pointer.

I agree that one should not expect a language change at this point.  But for
the sake of discussion, suppose we were considering changing the language
rules.  The next logical questions are:
1.  Is there a way to fix the problem without changing the current rules?
2.  Would fixing without causing more problems than the current rule?

I'd say the only way to solve the problem without a rule change is better
education of users.  While it is possible via a wrapper class to create a
simulation of a pointer to const object that cannot be deleted, that does
not solve the problem of naive users assuming that all they need to do is
declare the pointer to point to a const object.

So that leaves us with option 2, changing the language rules.  If the rules
were changed to prevent deleting pointers to const objects, programs would
have to be rewritten in one of the following ways:

1.  When you allocate, you must store the pointer in a pointer to non-const
object.  Then you can copy the pointer to a pointer to const object.  When
you delete, you use the pointer non-const object:

    T * ptr = new T;
    T const * cptr = ptr;
    //Use cptr
    delete ptr;

2.  When you allocate, store the pointer in a pointer to a const object.
When you delete, cast away the const.
    T const * cptr = new T;
    delete const_cast<T *>(cptr);

3.  As you suggest, this could be hidden in a wrapper class.  One could use
std::auto_ptr, if std::auto_ptr<T>::~auto_ptr were redefined as
        template<class T> std::auto_ptr<T>::~auto_ptr{
            delete const_cast<T *>(m_ptr);  //Cast away const before
deleting
        }

    Then one could use
        std::auto_ptr<const T> cptr = new T;
        // use cptr
        // when cptr goes out of scope, ~cptr is called, just like for a
const variable

    If one wanted to avoid the const_cast, one could design an alternative
class:
        template<class T> ConstObjectPtr{
        public:
            explicit ConstObjectPtr(T * ptr):m_ptr(ptr){};
            T const * Ptr(){ return m_ptr; };
            ~ConstObjectPtr(){ delete m_ptr };
        private:
            T * m_ptr;
        };
---
[ 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/04/03
Raw View
sirwillard@my-dejanews.com () wrote:
> delete doesn't change an object.  It just ends it's lifetime.  Lifetime
> is not a property of an object.

Surely it is. What else is it a property of?


> It makes sense, because if you couldn't delete a const pointer you'd be
> unable to free such memory _EVER_.

You could delete it through some other non-const reference (or through a
const-cast, which we'll ignore). Consider:

    void func() {
        Object temp;
        const Object &myObject( temp );
        //...
        // temp destroyed at end of scope.
    }

Or:

    void func() {
        Object *temp = new Object;
        const Object &*myObject( temp );
        //...
        delete temp;
    }

You appreciate that a "const" reference does not mean the object cannot be
changed; it means the object cannot be changed through that reference.


> Great way for the language to force memory leaks onto you, no?

That needn't follow. For auto and static objects the compiler would still
be free to delete the object behind the scenes, roughly as if it had
translated into the above "non-const temporary" model.

  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: Bruce Visscher <bvisscher@mindspring.com>
Date: 1999/04/03
Raw View
Dave Harris wrote:

> Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > Deleting a const pointer is ok (that's just common
> > sens anyway).
>
> I agree the standard says it is OK. I don't see that it is common sense.
> The destructor changes the state of the object, can and probably does
> overwrite its bytes with garbage etc. In what way is it a const operation?
>

But an object doesn't become const until after the constructor runs and ceases
to be const when the destructor starts.

Consider a const std::string.  It must allocate storage when it is created and
release this storage once it is destroyed.  How can it do either of these with
out altering its state?

Objects with constructors and/or destructors cannot reside in ROM.

Bruce Visscher
---
[ 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/04/03
Raw View
David Harmon <source@netcom.com> wrote in message
news:371beff6.161521780@nntp.ix.netcom.com...
> Still, maybe we need:
>
>    class foo {
>    public:
>        ~foo();
>        ~foo() const;

I felt once in need to be able to distinguish at construction time whether
an object is const or not. I'd like to be able to define a const constructor
and a const destructor. They would be able to perform non-const operations,
though. So that would be an exception to const methods. But ctors are
special methods anyway.

Andrei
---
[ 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: Bruce Visscher <bvisscher@mindspring.com>
Date: 1999/04/04
Raw View
Dave Harris wrote:

> sirwillard@my-dejanews.com () wrote:
> > delete doesn't change an object.  It just ends it's lifetime.  Lifetime
> > is not a property of an object.
>
> Surely it is. What else is it a property of?
>
> > It makes sense, because if you couldn't delete a const pointer you'd be
> > unable to free such memory _EVER_.
>
> You could delete it through some other non-const reference (or through a
> const-cast, which we'll ignore). Consider:
>
>     void func() {
>         Object temp;
>         const Object &myObject( temp );
>         //...
>         // temp destroyed at end of scope.
>     }
>
> Or:
>
>     void func() {
>         Object *temp = new Object;
>         const Object &*myObject( temp );
>         //...
>         delete temp;
>     }
>

So you're proposing that objects with destructors can't be const?  I for one
don't care for this idea.  And what about objects with constructors?

Currently, objects don't become const until the constructor completes and
cease to be const once the destructor begins.  I don't see a problem with
this.  Granted this implies that you can't put objects with
constructors/destructors into ROM.  I think that's a given anyway (what would
a ctor or dtor be able to do if they can't modify the objects state?).

Bruce Visscher
---
[ 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/04/04
Raw View

Dave Harris wrote in message ...
>sirwillard@my-dejanews.com () wrote:
>> delete doesn't change an object.  It just ends it's lifetime.  Lifetime
>> is not a property of an object.
>
>Surely it is. What else is it a property of?


Nothing. It's not a property.





[ 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: source@netcom.com (David Harmon)
Date: 1999/04/04
Raw View
On 03 Apr 99 14:59:37 GMT in comp.std.c++, Bruce Visscher
<bvisscher@mindspring.com> wrote:

>Consider a const std::string.  It must allocate storage when it is created and
>release this storage once it is destroyed.  How can it do either of these with
>out altering its state?

It can do the latter by deleting a pointer to the allocated storage.
---
[ 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/04/05
Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>Egerton Nick Vg23 X3213 wrote:
>> Anyway, should the following compile:
>>   const int * ip = new int;
>>   delete ip;
>
>Deleting a const pointer is ok (that's just common sense anyway).

It is most emphatically not common sense.  It was hotly debated in
full committee.  Enough members of the full committee made the
same logical error that I see repeated in this forum, that the
error became enshrined in the standard.

The result is that a whole class of preventable errors are
not caught by a standard-conforming compiler, and it is now
impractical to warn about them either.  This is unfortunate.
C++ does show some evidence of "design by committee", and this
is one of the more egregious, because it is so gratuitous.

Dressing it up as "common sense" doesn't make it so.  It's a
design bug we must live with.  Programs that rely on it are
badly designed.

--
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/04/05
Raw View

David Harmon wrote in message <3740666b.257397323@nntp.ix.netcom.com>...
>On 03 Apr 99 14:59:37 GMT in comp.std.c++, Bruce Visscher
><bvisscher@mindspring.com> wrote:
>
>>Consider a const std::string.  It must allocate storage when it is created
and
>>release this storage once it is destroyed.  How can it do either of these
with
>>out altering its state?
>
>It can do the latter by deleting a pointer to the allocated storage.


Which would typically be followed by a pointer = 0 operation, for the usual
reasons, which is a non-const operation.





[ 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/04/05
Raw View
kuyper@wizard.net (James Kuyper) wrote:
> Being 'const' is a matter of the difference between the initial
> and final states of an object.

This may be the difference in our perspectives. I see it more as a
property of an interface to an object, a restriction on what can be done
through that interface. To me the difference between having a state and
not having a state, or between being able to use other methods and not
being able to use them, is a big difference that defies the notion of
"const"ness.

For example:
    void anotherProc( const Object * );

    void proc( const Object &object ) {
        object.method1();
        anotherProc( &object );
        object.method2();   // May fail; object may be deleted.
    }

You are arguing that anotherProc() should not be able to change the
object's state but should be able to delete it altogether. For me this
rather spoils the point of having 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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/04/05
Raw View
Siemel Naran wrote in message ...

>To add to your point, consider:
>   struct X {
>      int x;
>      ~X() { non_const_member_function(); }
>      void non_const_member_function() { x=0; }
>   };
>The destructor calls a non-const member function.  Now a program,
>   int main() {
>      X const * x=new X();
>      x->non_const_member_function(); // error
>      delete x; // ok!
>   }
>


The constructor, too, can call a non-const member function and can
initialize const data members. I doubt that anyone would argue that the
constructor should not be permitted to act upon non-const members for a
const object.

Construction and destruction are, in my view, separate from the state of an
object. The analogy to lifetime is flawed. A destroyed object, and
consequently one under destruction, has no properties of interest to the
object's users because there is no cadaver to deal with once construction is
complete. The object simply ceases to be, said cessation being a product of
the destructor, which needs all necessary privileges to destroy. Otherwise,
a program could not automatically destroy a const object that was declared
as auto,  extern or static.

Someone said elsewhere that this subject was hotly debated in full
committee. Perhaps the members who participated can present those arguments
here for the rest of us
---
[ 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/04/05
Raw View
Dave Harris wrote in message ...
>kuyper@wizard.net (James Kuyper) wrote:
>> 'const' inhibits operations that change the value of the object; it has
>> no relevance to operations that cause the object to cease to exist. If
>> it did, then logically it should also prohibit operations that bring
>> them into existence.
>
>I don't see how that follows. How can something that doesn't exist be
>const?

Exactly. And once the destructor is called, the object ceases to exist from
the perspective of the program that instantiates the object. Unless, of
course, the destructor throws an exception, which opens another container of
crawly creatures.
---
[ 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: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 1999/04/05
Raw View
>>>>> "NM" == Nathan Myers <ncm@nospam.cantrip.org> writes:

NM> Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:

>> Deleting a const pointer is ok (that's just common sense anyway).

NM> It is most emphatically not common sense.

I agree that it is not common sense. As soon as somebody disagrees
with an assertion, the others should stop pretending it is common
sense. Isn't _that_ common sense? :-)

Anyway, what's wrong with Andrew Koenig's point that we have anyway to
accept that local variables (const or not) are indeed deallocated, and
better so?

http://x13.dejanews.com/[ST_rn=ps]/getdoc.xp?AN=462016291&CONTEXT=923323079.983433239&hitnum=10

This said, shouldn't we stop speaking of design bug in the language?
This doesn't seem more justified that the "common sense" position...

Best Regards!
Marc

--
Marc Girod                Hiomo 5/1          Voice:  +358-9-511 23746
Nokia Telecommunications  P.O. Box 320       Mobile: +358-40-569 7954
NWS/NMS/NMS for Data      00045 NOKIA Group  Fax:    +358-9-511 23580
                          Finland            marc.girod@ntc.nokia.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: scorp@btinternet.com (Dave Harris)
Date: 1999/04/07
Raw View
fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> There's an analogy with the Unix permissions system.
> It may come as a surprise to some that under Unix,
> a user can delete a file to which they have only read-only
> access permission; they just need write access to the directory.
> But once you understand how the Unix file system works, then this
> seems quite natural, and right.  Indeed it would be silly if you
> could make a link to a read-only file and then not be able to delete
> the link.  So the idea of being able to delete something even though
> it is "read-only" may indeed be common sense, to experienced Unix
> hackers ;-)

The key word here is "unlink". "Unlink" is an action performed on a
directory, not a file. The analogous operation would surely be assigning 0
to the pointer.

    const Object *pObject = new Object;
    //...
    pObject = 0;  // Perfectly alright!

The analogy breaks down because Unix has a garbage collection system based
on reference counting, and C++ does not, so the above is a memory leak.
But we can add simple GC with a wrapper class similar to std::auto_ptr.

So it seems to me the Unix permissions analogy argues against the new
rule, if your Unix hacker understands it properly.


> Some other operating systems have more fine-grained
> capability-based security systems.

Another difference is that Unix stores the permissions with the inode
(that is, the file), rather than with the name (that is, the directory
entry). As far as I know it is not possible to have a Unix file writable
under one alias and readonly under another. I don't think this affects the
argument, though.

  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: "John D. Hickin" <hickin@hydro.cam.org>
Date: 1999/04/07
Raw View
I would agree that destruction of an object is most definitely not a
const operation. It is, however, logically const, and this may be the
key.

I argue that destruction is logically const because no observation that
you may undertake afterwards can detect a change of state.

Regards, John.
---
[ 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/04/07
Raw View
ark@research.att.com (Andrew Koenig) wrote:
> But there is no such guarantee anyway, even if the type system is
> completely strict about const, because f might have a non-const alias
> to p that it obtained from another source.

But that is true for all const operations, not just operator delete(). You
seem to be arguing that const has no value at all. Or perhaps you are just
nit-picking?

It seems clear to me that const does have value as part of an interface
declaration, and that value is diminished by allowing const objects to be
deleted.

  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/04/07
Raw View
mseitz@meridian-data.com (Matt Seitz) wrote:
> Ah, now I see both sides of the argument.

Quite so.


> Is there any way to make both sides happy?

Of course it is too late now, but the old rule plus a standard wrapper
class looks good to me. No-one has come up with any problem with the class
you suggested earlier, which I'll reproduce here in case it has been
over-looked:

        template<class T> ConstObjectPtr{
        public:
            explicit ConstObjectPtr(T * ptr):m_ptr(ptr){};
            T const * Ptr(){ return m_ptr; };
            ~ConstObjectPtr(){ delete m_ptr };
        private:
            T * m_ptr;
        };

Does anyone know if the committee considered this approach? If so, why did
they reject it?

  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: James Kuyper <kuyper@wizard.net>
Date: 1999/04/07
Raw View
Dave Harris wrote:
...
> An object does not become const until its constructor is finished.

And it ceases to be const as soon as the destructor starts, which is a
nicely symmetrical rule. The arguably non-const behavior of deleting it
doesn't occur until after it's been destroyed.


[ 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: "J.Barfurth" <techview@bfk-net.de>
Date: 1999/04/07
Raw View

Nathan Myers schrieb in Nachricht <7edokk$mgo$1@shell7.ba.best.com>...

>There is no such thing as a const object on the heap.  There are
>only pointers-to-const resulting from conversion from the pointers
>to the non-const objects on the heap.  (Only static and auto objects
>can actually be const.)  Casting away const on a pointer to an
>actually non-const object is well-defined, and that's what we're
>talking about.


Does this mean, that 'new' actually ignores top-level constness ? Like:
    const T* p = new const T();          // *p is _actually_ non-const
    const_cast<T*>(p)->change();    // results are well-defined
Even if this is the case, the intent of the

>The comparison to auto const objects is argument by analogy
>(and thus fraudulent) as explained and exemplified elsewhere.
>It was arguments of the caliber of Steve's, and Andrew's (quoted
>in my other posting), and none better, that persuaded the committee
>to change the rule and introduce this design flaw.


I used to never delete through const pointers, mostly sharing the arguments
raised by others on this thread. This 'style rule' was unconciously
introduced by the historical behaviour of compilers though. Recently Siemel
Naran and myself touched this topic in the discussion of casting 'operators'
for smart pointers on comp.lang.c++.moderated. I started to like the new
rule since, as it permits to have templated smart pointers to const objects,
without partially specializing for const types (which at least M$VC does not
permit yet).

The main argument against the new rule I've seen in this discussion was
that, when passing around const pointers [I will use this as a shorthand for
'pointer-to-const'] the object pointed to is supposed to stay unchanged
(thru this reference). 'Unchanged' here would mean (1) it will continue to
exist and (2) no non-const behaviour will be invoked. I will return to (1)
later on. (2) is a concern, because the object's destructor may invoke
non-const members and change contained objects' state before the existence
of the object is ended.

To be more concrete: An object maintains an external resource. Constness
semantics of the object are that there will be no change in that resource's
state. The destructor may change the state of that resource (e.g. finalizing
it somehow - consider class CDWriterSession). While allowing others
read-only access to that resource by handing out a const pointer, a context
(class,module,function,thread,..), that exclusively has non-const access to
the object, may assume that it can continue modifying the resource
uninterrupted.

[BTW: In this discussion we should disregard cases of aliasing thru a
non-const pointer (any problems caused by this would be the same regardless
of which rule applies) or 'const_cast'ing (which is valid only in a limited
set of cases and is a deliberate violation of constness anyway).]

So what (1) and (2) above have in common is a notion of ownership. The rule
not to delete an object through a const pointer (be it a style rule or
enforced by the language) is really a rule about ownership.
It really becomes meaningful only when a pointer is handed from one context
to another. In this respect it is somewhat like const-correctness (Declaring
an auto or static variable const is primarily a statement of
self-restriction: "I needn't and wont modify this object").  [Read on before
getting angry at me]

Our rule could then be restated as "Passing a const pointer from one context
to another should not transfer ownership" or "const pointers carry no
ownership". 'Ownership' here again has the two aspects mentioned above: (1)
control of lifetime and (2) control of modification.

There is a strong feeling (at least I have), that these two aspects are
interrelated.
Let's call the context having control of an object's lifetime the 'owner'.
The initial owner creates the object. The owner can only change, if the
current owner willingly transfers ownership(1) to another context (or allows
the other context to seize ownership - which amounts to the same). If this
is not the case, there will be trouble anyhow - multiple owners will
eventually destroy the object multiply.
OTOH ownership(2) can be shared. But the owner also must somehow control
which other contexts currently can access the object at all. In the
beginning (just after creation) the owner is _normally_ the only one having
any access, so it is the ultimate source of all references to the object. By
virtue of this, the owner also ultimately controls who is given modifying or
non-modifying access to the object. From this it seems natural to say that
ownership(1) would imply ownership(2). So when denying modifying access by
not making available non-const pointers to others, ownership of lifetime
should not be made available to others either.

So far I have given an argument, which suggests that it is *good* to prevent
ending objects' lives through a const pointer. It is based on semantics
commonly given to const pointers.

By this argument, allowing const members in objects or local const objects
would only be an unimportant feature of the language. (For now ignoring the
usefulness of objects being _actually_ const).

OTOH most would say that having const members in objects or local const
objects is *good*. They make explicit and enforce the intent not to invoke
non-const behavior on an object during its lifetime. Here construction and
destruction of the object are *not* part of its lifetime proper. (IMHO they
are not: when a c'tor or d'tor is executed we _generally_ dont have the full
dynamic type available.)


Author: James Kuyper <kuyper@wizard.net>
Date: 1999/04/07
Raw View
Egerton Nick Vg23 X3213 wrote:
>
> For those interested the standard is pretty explicit. In Section 5.3.5
>
> clause 2 note 2 of ISO/IEC 14882 (first edition 1998-09-01) page 81
> it states:
>
> "Note: a pointer to a const type can be an operand to a
> delete-expression;
> it is not necessary to cast away the constness of the pointer
> expression
> before it is used as the operand of the delete-expression."

That's not an issue here; what's being debated is whether the standard
should say that.


[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/07
Raw View
scorp@btinternet.com (Dave Harris) writes:

>The main motivation for allowing it seems to be cases like:
>
>    void proc() {
>        const Object *pObject = new Object;

Or cases like this:

  const Object *pObject = new const Object;

>        //...
>        delete pObject;
>    }
>
>where we are imitating auto scope. Pragmatically, this is a rather weak
>argument. We can deal with it by using a wrapper class similar to
>auto_ptr<>. To me the case is similar to:
>
>    void proc() {
>        Base *pBase = new Derived;
>        pBase->derivedMethod(); // Compile error.
>    }
>
>We correctly forbid this

The modified example using `new const Object' is not similar to
that case.  Instead, it is a much closer analogy to the
case below, which is allowed:

>even though we allow:
>    void proc() {
>        Derived *pDerived = new Derived;
>        pDerived->derivedMethod(); // OK!
>    }

Now, once you see that the example using `new const Object'
should be legal, by analogy with the example immediately
above using `Derived', then it becomes clear that in this
analogy the (psuedo-)class `const Object' has a `delete'
(pseudo-)method.  So the earlier example using `new Object'
should be legal too, because the call to delete is analagous
to `pBase->baseMethod()' not `pBase->derivedMethod()'.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.


[ 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@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/04/07
Raw View
On 07 Apr 99 15:40:52 GMT, Andrew Koenig <ark@research.att.com> wrote:

>Ah -- I just remembered the killer argument.

You posted this in comp.lang.c++ about six months ago.
It satisfied my curiosity for about a week.
But now I maintain my position that in "delete x", 'x' must not have a
first level const.  Eg,
   X * x=new X(1);
   delete x; // ok: 'x' is not pointer to const
It doesn't matter if 'x' has const data inside it.


> class X {
> public:
>  X(int n0): n(n0) { }
> private:
>  const int n;
> };

Here's my way of thinking.
1. The expression "X::operator new(sizeof(X))" creates a stack big
   enough to hold an X object.
2. The expression "X(0)" creates in this stack an X object.  This
   X object is created as a stack object.
3. The expression "x->~X()" destroys a stack object.  It doesn't
   matter if the object has const data inside it.  Eg,
      int main() { const int i=1; } // 'i' destroyed though it it const
   Similarly, this should present no problem
      int main() { X * x=new X(0); delete x; }
4. The expression "X::operator delete(x,sizeof(X))" removes the
   stack space.  The constraint is that 'x' should be a pointer to
   non-const.


>Now, if we say
>
> X* xp = new X;

This should be
  X* xp = new X(0);

>then saying
>
> delete xp;
>
>deletes a const object, namely member xp->n, and there is no way
>to cast away the const that applies to it.

The const inside 'xp' don't matter.

--
----------------------------------
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: stanley@west.sun.com (Stanley Friesen [Contractor])
Date: 1999/04/07
Raw View
In article <memo.19990407023803.5569D@btinternet.com>,
Dave Harris <brangdon@cix.co.uk> wrote:
>fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
>> seems quite natural, and right.  Indeed it would be silly if you
>> could make a link to a read-only file and then not be able to delete
>> the link.  So the idea of being able to delete something even though
>> it is "read-only" may indeed be common sense, to experienced Unix
>> hackers ;-)
>
>The key word here is "unlink". "Unlink" is an action performed on a
>directory, not a file.

Except that in Unix a file is reference counted, and when the last link goes
away, so does the file.  So unlinking can indeed destroy the file.

> The analogous operation would surely be assigning 0
>to the pointer.

Actually it is closer to destructing a smart pointer to the const object.
---
[ 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/04/07
Raw View
Andrew Koenig<ark@research.att.com> wrote:
>Nathan Myers <ncm@nospam.cantrip.org> wrote:
>> It was arguments of the caliber of Steve's, and Andrew's (quoted
>> in my other posting), and none better, that persuaded the committee
>> to change the rule and introduce this design flaw.
>
>Ah -- I just remembered the killer argument.
> struct X { const int n; X(int n0): n(n0) { } };
>Now, ...
> delete xp;
>deletes a const object, namely member xp->n, and there is no way
>to cast away the const that applies to it.
>
>So either you have to allow const objects to be deleted, or you have
>to say that there are some objects that are not themselves const
>but that cannot ever be legitimately deleted.
>
>I am pretty sure that this is the argument that swung the committee vote.

I don't recall this argument coming up in committee.

If it did, it's irrelevant.  Member X::n is not a const object; it
is a const subobject.  The ARM rule didn't disallow the delete,
so this example would not have justified a change to the ARM rule.

If, as Andrew seems to recall, this argument swayed the committee,
then it demonstrates my point that the committee was swayed by
(a series of) invalid arguments.

Andrew's other example:

  template <typename T> void f(T* tp)
    { T* tp2 = new T(*tp); delete tp2; }

where T might be bound to "const X", is similarly unpersuasive.

The point of the ARM rule was that this dangerous practice of
deleting (what might be) constant pointers is explicit.  His
example above can be rewritten under the ARM rule as:

  template <typename T> void const_deleter(T const* tp)
    { delete const_cast<T*>(tp); }

  template <typename T> void f(T* tp)
    { T* tp2 = new T(*tp); const_deleter(tp2); }

with an improvement in clarity.

I usually expect somebody to raise at this point an argument
that since const can be cast away anywhere in a program, const is
meaningless anyway.  The answer, as usual, is that casts can be
searched for, if they are new-style, or warned against, if they
are not.  (That was one of the reasons for adding the new-style
cast.)  The purpose of the type system is not to make dangerous
or invalid operations impossible, but to make them explicit.

A const_cast in a delete-expression would be an explicit
acknowledgement that one is doing something potentially dangerous.
Now that the ARM rule has been broken there is nothing to
flag that fact, in this case.

The simplest way to recognize the problem is to note that
the destructor is not a const member.  I.e., it does and
must do things which would be warned about in a const member.

The analogical argument about auto objects doesn't apply,
because it is not the user who calls the destructor, but
the compiler, and only after the object has gone out of
scope and no longer exists.  (There is no safety issue there.)

Arguments I have seen posted that argue it's OK to delete through
a const pointer because "after delete is called the object doesn't
exist anymore" are circular, and I am disappointed in those people
who argued it.  (As Andrew once said, famously, "What have you been
smoking?")  The issue is whether to allow delete to be called.
What happens after is a separate matter, and not in dispute.

The new rule remains a design flaw.  Cfront had it right, the
committee broke it.  If that is the biggest thing the committee
broke we are in pretty good shape.

--
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/04/07
Raw View
Herr Barfurth raises some interesting issues (finally).

J.Barfurth<techview@bfk-net.de> wrote:
>Nathan Myers schrieb in Nachricht <7edokk$mgo$1@shell7.ba.best.com>...
>>There is no such thing as a const object on the heap.
>
>Does this mean, that 'new' actually ignores top-level constness ? Like:
>    const T* p = new const T();          // *p is _actually_ non-const
>    const_cast<T*>(p)->change();    // results are well-defined

Yes.  There is no operator const_new().  Operator new() returns
a non-const pointer which is passed to the constructor.

>I started to like the new
>rule since, as it permits to have templated smart pointers to const objects,
>without partially specializing for const types (which at least M$VC does not
>permit yet).

It is always more convenient, on some scale, when restrictions
are removed, until you encounter the reason for the restriction.
("The fence around that snake pit certainly interfered with
traffic.")  Compatibility with compiler bugs, though, makes a
singularly unpersuasive argument, at least to me.  :-)

>[...]
>So far I have given an argument, which suggests that it is *good* to prevent
>ending objects' lives through a const pointer. It is based on semantics
>commonly given to const pointers.

It was a persuasive argument.

>By this argument, allowing const members in objects or local const objects
>would only be an unimportant feature of the language. (For now ignoring the
>usefulness of objects being _actually_ const).

True.  Const members primarily help protect against errors in members,
though they also allow (in the case of static members) a nice way
to declare manifest constants.

>From this it seems reasonable to say that having control of an objects
>lifetime (a function certainly has such control of local auto variables)
>does not necessarily imply having modifying access.
>By the same token, why should the owner of an object on the freestore have
>to keep available to herself [are classes or functions female ? - in German
>they are ;-)]  a non-const reference for the only purpose of using it to
>delete the object. If it is the case that the context having control of an
>objects lifetime shouldn't (and won't) modify an object during its lifetime
>(as restricted above), there should also be a way to express this. By the
>current rule in the standard there is such a way: the owner retains only a
>const pointer to the object, which will be sufficient for deletion. [See (*)
>below for an example]
>IMO this argument (though by analogy) is not fraudulent, at least not if
>made explicit this way.
>
>Thus we have a strong case in favor of the rule that currently is standard.

No.  You have an argument that the current rule doesn't break
*everything*, only some things.

>OTOH lets have a look at our previous argument against that rule. Why should
>passing a const pointer to a function imply that ownership(1) [=control of
>lifetime] is not transferred, while passing a non-const pointer is
>completely neutral in this respect. Proper lifetime management is up to the
>developer in any case. The semantics of any function receiving a pointer as
>a parameter as to whether this pointer will be deleted by the called context
>or not must be specified, regardless of any const on this pointer.

Under the ARM rule, a function that took a const pointer was
known not to take ownership.  Now, you know less.  This is
precisely the problem.

>In another post Nathan Myers writes:
>>A local const variable is being destroyed with full knowledge of its
>>creator, in the same context where it was created, and where it is
>>lexically impossible to try to continue using it.  Destruction in
>>some random other context is in no [way] equivalent.
>
>... as the language
>doesn't protect you from doing that through a non-const pointer, why
>should it do that for const pointers ?

Specifically because when I declared the pointer const I was making
a promise.  I cannot keep that promise any more:

  void f(const T* p) { g(p); }

Before, I didn't need to know anything about g in order to make
the promise, in declaring f, that it would not do damaging things
with its argument p.  (As usual, modulo casts, wild pointers, etc.)
Now I can make no such promise.

>I still maintain as a style rule, that const pointers received from another
>context *generally* should not be deleted. But I *generally* apply the same
>rule to non-const pointers as well. When ownership of object lifetime is
>transferred, I prefer using something like auto_ptr<>. Where it is
>appropriate (usually hidden in a class, which often is a template
>instantiation) I prefer being able to delete through a const pointer,
>instead of resorting to const_cast or partial specialization on constness.

If you are violating a rule in deleting the pointer, why object
to a requirement that you use a const_cast<> to signal your
awareness that you are violating the rule?

--
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: "J.Barfurth" <techview@bfk-net.de>
Date: 1999/04/08
Raw View
Siemel Naran schrieb in Nachricht ...
>On 07 Apr 99 15:40:52 GMT, Andrew Koenig <ark@research.att.com> wrote:
>Here's my way of thinking.
>1. The expression "X::operator new(sizeof(X))" creates a stack big
>   enough to hold an X object.
>2. The expression "X(0)" creates in this stack an X object.  This
>   X object is created as a stack object.
>3. The expression "x->~X()" destroys a stack object.  It doesn't
>   matter if the object has const data inside it.  Eg,
>      int main() { const int i=3D1; } // 'i' destroyed though it it cons=
t
>   Similarly, this should present no problem
>      int main() { X * x=3Dnew X(0); delete x; }
>4. The expression "X::operator delete(x,sizeof(X))" removes the
>   stack space.  The constraint is that 'x' should be a pointer to
>   non-const.

This seems to be a new argument, orthogonal to the ones I've seen so far =
!
I'll try to rephrase the key parts of your argument. Correct me if I'm
wrong.

A delete-statement invokes two actions: calling a destructor and invoking
the appropriate operator delete.
3) There is no problem with calling the destructor for a const
object(although this in turn might invoke additional non-const behaviour).
4) OTOH, operator delete should be invoked only for a non-const pointer.
[Why ? See below !]

In code:
    delete x;    // having X const* x;
can be replaced by
    x->~X();    // allowed
    X::operator delete(x);    // not allowed:
    // no conversion from X const* to void*
    // conversion loses (cv-) qualifiers

My Comments:
About 3):
- Destructors (like constructors) somehow 'transcend' constness anyhow. T=
hey
have to, in order to allow auto and static const objects.
-This has been used on this thread as an argument in favor of the standar=
d's
rule. IMHO this argument is valid (though by analogy). By your argument t=
his
analogy doesn't matter in our current discussion.
-The old cfront behaviour to allow an explicit destructor call x->~X()
through a const pointer (i.e. pointer to const) is consistent with this
rule.
- This rule can be justified by considering execution of c'tors and d'tor
to, in a way, occur outside the lifetime of the object. An object fully
exists only when construction is finished and before destruction has
commenced. Constness (as a property of the object) only applies during th=
e
(thus restricted) lifetime of the object.
- POD types (by definition) dont have this transition phase. To argue
against the old ARM rule by denying (3) would suggest that POD and non-PO=
D
types are different in this respect. But nobody proposed to allow deletin=
g
through a const pointer for POD, while disallowing it for non-POD types. =
Yet
;-)

About 4):
- The signature of any operator delete is void operator delete(/*no
const!!*/ void *, ...) !
- There should be as little difference in semantics (especially access) a=
s
possible between explicitly invoking a function and an implicit
(compiler-generated) invocation as possible. [This has been denied by
proponents of the ARM rule when arguing against (3); as your argument sta=
tes
that (3) is not relevant to this discussion, proponents of the ARM rule c=
an
drop this denial.] To justify this rule consider that the compiler will
*not* invoke private c'tors and d'tors for global objects. I also don't
recall any instance of allowing the compiler to violate constness in the
standard. I explained above why I don't consider (3) to be such a violati=
on.
- From the preceding follows: the compiler should not be allowed to invok=
e
operator delete on a const pointer.
- Don't allow deallocating memory through a const pointer: it might be RO=
M !

Although I'm not yet convinced that I want to follow this argument all th=
e
way, it gives this discussion an interesting twist:
- No more breaking analogies or unexplained asymmetries.
- The difference between { T const* p =3D new T(); delete p; } and { T co=
nst
t; } is moved to where it obviously exists: memory (de-)allocation.
- None of the arguments so far addressed the issue of POD vs. non-POD typ=
es.
(IIRC the original post was about deleting a int const*, which needn't be
affected by discussion of mutating destructors). I discovered this potent=
ial
problem only this morning and now it's gone already :-).

Eager to see any comments.

-- J=F6rg
---
[ 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/04/08
Raw View
Al Stevens <alstevens@midifitz.com> wrote in message
news:_84O2.14004$mv3.872496@newscene.newscene.com...
> There's the rub. The destructor can, in the service of destruction, call
> non-const functions of other classes and do non-const things outside its
own
> realm. But, as others have pointed out, that's true too for the automatic
> destruction of local const objects, and externs, too. I don't see the
> difference. Perhaps someone can explain the philosophical difference
between
> destroying objects with delete and automatic destruction other than just
> saying that there is one.

Give me a shot: destruction of statically-allocated objects is deterministic
and done automatically by the compiler. Destruction of dynamically-allocated
objects is non-deterministic and done manually by the programmer. So to say,
from compiler's standpoint, destruction time and place for
dynamically-allocated variables is totally random.

> Following your argument, one could conclude that a destructor, even for a
> non-const object, should not be permitted to mess with const data members
of
> its own class.

I'm not sure whom argument is here about, but reading all the thread I
haven't got to the same conclusion.

> I keep hearing here from some that deleting a pointer to a const object
> should not be permitted, but I do not hear any compelling reason why.

A pragmatic reason is that it allows bugs to happen. It's a loophole. People
calling functions that take const arguments expect those functions to leave
the objects unmodified. Just as they were. Forever young. This is what const
is all about. The fact that a function taking a pointer to const cannot
modify the object, but can very easily blow it up, is hard to swallow for
me.
I would expect calling a function that takes a pointer-to-const several
times against the same object and not seeing any change in the object. If
the function doesn't have side effects, I expect it to be a function in
mathematical sense - takes parms, returns result, and that's it. Just like
in functional languages.
To say that destruction doesn't change state is a bit unintuitive. If I use
a deleted object, I certainly will detect a change.

The gist is this fragment:

void f(const T *);
void g(const T * p)
{
    cout << *p;
    f(p);
    cout << *p;
}

Following my conceptual view on const, and every rule in the language except
the one we're discussing, I would expect to see the same object printed out.

Andrei
---
[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/08
Raw View
scorp@btinternet.com (Dave Harris) writes:

>fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
>> There's an analogy with the Unix permissions system.
>> It may come as a surprise to some that under Unix,
>> a user can delete a file to which they have only read-only
>> access permission; they just need write access to the directory.
>> But once you understand how the Unix file system works, then this
>> seems quite natural, and right.  Indeed it would be silly if you
>> could make a link to a read-only file and then not be able to delete
>> the link.  So the idea of being able to delete something even though
>> it is "read-only" may indeed be common sense, to experienced Unix
>> hackers ;-)
...
>The analogy breaks down because Unix has a garbage collection system based
>on reference counting, and C++ does not

Well, I was really talking about the Unix permissions analogy in
quite general terms: Unix permissions shows it can make sense for
delete permission and write permission to be separate.
I wasn't suggesting that the meaning of C++ `const' should be designed
based on a direct analogy with Unix permissions.

>So it seems to me the Unix permissions analogy argues against the new
>rule, if your Unix hacker understands it properly.

No; your argument showed that unlinking is not a good analogy to delete,
and I agree with that.  But the result is just that the direct
analogy with Unix permissions doesn't give us any guidance one way
or the other with regard to C++ `const' and delete permission,
since Unix permissions don't have anything analagous to C++'s delete.

The direct analogy that I was advocating was with capability-based
systems.  Unix permissions do constitute a simple capability-based
system, with the three main capabilities "read", "write", and
"execute".  There's no "delete" capability because Unix doesn't
have delete, instead it has reference counted garbage collection.

The argument as to why "delete" capability should not be part
of the C++ const system is not by direct analogy with Unix.
The argument is just that object lifetimes are fundamentally
different to modifiability.  C++'s const system does (for the
most part) enable compile-time verification that `const'
objects are not modified.  But C++'s approach to memory management
means that we could not hope to provide the same kind of guarantees
about object lifetimes, at least not without something very
different to `const'.  (I have heard that LC-LINT offers some
annotations that you can put on pointers to provide guarantees
about object lifetimes.  But `const' is not sufficient.)
If we were to try to provide guarantees about object lifetimes
with `const', such guarantees would necessarily be incomplete.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ 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: Marco Dalla Gasperina <marcodg@pacifier.com>
Date: 1999/04/08
Raw View
Andrew Koenig <ark@research.att.com> wrote:

> Ah -- I just remembered the killer argument.

>  class X {
>  public:
>   X(int n0): n(n0) { }
>  private:
>   const int n;
>  };

> Now, if we say

>  X* xp = new X;

> then saying

>  delete xp;

> deletes a const object, namely member xp->n, and there is no way
> to cast away the const that applies to it.

Hmmm.... does it?  It looks like a const object is being destroyed
in the process of invoking the delete operator on a pointer to the
containing object.  I don't think the argument is that a const object
can't be destroyed, but that you shouldn't be able to use the delete
operator on a const pointer.

Am I just splitting terminological hairs?

marco
---
[ 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: Matt Austern <austern@sgi.com>
Date: 1999/04/08
Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:

> On 07 Apr 99 15:40:52 GMT, Andrew Koenig <ark@research.att.com> wrote:
>
> >Ah -- I just remembered the killer argument.
>
> You posted this in comp.lang.c++ about six months ago.
> It satisfied my curiosity for about a week.
> But now I maintain my position that in "delete x", 'x' must not have a
> first level const.  Eg,
>    X * x=new X(1);
>    delete x; // ok: 'x' is not pointer to const
> It doesn't matter if 'x' has const data inside it.

What Andy's example does mean, though, is that you can't forbid
    "delete x"
by making general rule about about destructors and const objects.
Forbidding it would require a special-case rule dealing with the
specific syntactic construct of a delete-expression.  We would then
have to worry, on a case-by-case basis, about other syntactic
constructs that can result in a destructor getting invoked.

I wasn't on the committee when it made the decision to allow delete
through a const pointer, but I don't think it's an unreasonable
decision.  The rules to forbid "delete x", while allowing other
obviously reasonable things, would start to get complicated.
---
[ 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/04/08
Raw View
Andrew Koenig wrote:

> That argument is not particularly important in that particular form.
> The form that is important is
>
>         template<class T> void proc(args) {
>                 T *tp = new T;
>                 // ...
>                 delete tp;
>         }
>
> Now, you don't know whether T is a const type.  If you could not say
> "delete tp;" directly, there is no cast you could write that would allow
> it.

Please allow me to paste from the email conversation we've had. I hope the
news server works now.

 template<class T> inline T * const_away_cast(const T * tp)
 {
  return const_cast<T *>(tp);
 }

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

Andrei
---
[ 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: Biju Thomas <b_thomas@ibm.net>
Date: 1999/04/08
Raw View
Nathan Myers wrote:
>
> J.Barfurth<techview@bfk-net.de> wrote:
> >Nathan Myers schrieb in Nachricht <7edokk$mgo$1@shell7.ba.best.com>...
> >>There is no such thing as a const object on the heap.
> >
> >Does this mean, that 'new' actually ignores top-level constness ? Like:
> >    const T* p = new const T();          // *p is _actually_ non-const
> >    const_cast<T*>(p)->change();    // results are well-defined
>
> Yes.  There is no operator const_new().  Operator new() returns
> a non-const pointer which is passed to the constructor.
>

I think we are talking about new expression here, not operator new. A
note in 5.3.4 para 1 of the standard says:

====
the type-id [in the syntax for the new-expression] may be a cv-qualified
type, in which case the object created by the new-expression has a
cv-qualifid type.
====

Doesn't this mean that there can be const (and volatile) objects on the
heap?

Regarding operator new returning a pointer to some const (ie, read-only)
pointer, wouldn't it be possible to write a class specific allocator,
which may return a pointer to some read-only storage?

Best regards,
Biju Thomas



[ 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/04/08
Raw View
Matt Seitz wrote:
>
> Dave Harris wrote in message ...
> >I'm not expecting a language change now; I'm just registering surprise
> >that people think this behaviour is "common sense".
>
> I see your point that a reasonable person might expect that by declaring a
> pointer to a const object that one could not delete the object using that
> pointer.
>
> I agree that one should not expect a language change at this point.  But for
> the sake of discussion, suppose we were considering changing the language
> rules.  The next logical questions are:
> 1.  Is there a way to fix the problem without changing the current rules?
> 2.  Would fixing without causing more problems than the current rule?
>
> I'd say the only way to solve the problem without a rule change is better
> education of users.  While it is possible via a wrapper class to create a
> simulation of a pointer to const object that cannot be deleted, that does
> not solve the problem of naive users assuming that all they need to do is
> declare the pointer to point to a const object.
>
> So that leaves us with option 2, changing the language rules.  If the rules
> were changed to prevent deleting pointers to const objects, programs would
> have to be rewritten in one of the following ways:
>
> 1.  When you allocate, you must store the pointer in a pointer to non-const
> object.  Then you can copy the pointer to a pointer to const object.  When
> you delete, you use the pointer non-const object:

[...]

How would you store the pointer created with the following code?

class X {};
typedef X const cX;

??? p = new cX;

There are two possibilities:

X* p = new cX; // already forbidden today: the created object is const!
cX* p = new cX; // would be forbidden with your change.

Also note that

delete const_cast<X*>(p);

would trigger undefined behaviour if destructing an object would be
considered a modifying operation, since this time, we have not just a
pointer to const pointing to a non-const object, but this time the
object itself is const.

BTW, one could consider the constructor not honoring const a hole
as well, since you can write:

class X
{
public:
  X(): i(0), myself(this) {}
  void change() const { myself->i++; }
  int i;
private:
  X* myself;
};

int main()
{
  X const x;
  int const i=x.i;
  x.change(); // allowed: change is a const method
  assert(i==x.i); // fails - and there was no const_cast at all!
}


[ 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 <leichter@smarts.com>
Date: 1999/04/08
Raw View
| > But now I maintain my position that in "delete x", 'x' must not have
| > a first level const.  Eg,
| >    X * x=new X(1);
| >    delete x; // ok: 'x' is not pointer to const
| > It doesn't matter if 'x' has const data inside it.
|
| What Andy's example does mean, though, is that you can't forbid
|     "delete x"
| by making general rule about about destructors and const objects.
| Forbidding it would require a special-case rule dealing with the
| specific syntactic construct of a delete-expression....

There's actually no problem here.  What is being argued is that the
*programmer* should not be able to invoke operator delete - or the
destructor - on a const object.  That has nothing to do with how the
*compiler* arranges for various implicit deletions to take place.  We
can simply say that any implicit destruction/deletion - at the end of
scope for an automatic variable, at program exit for a static, during
deletion of contained objects - is interpreted as if applied to the
object with constness cast away.  Thus:

 { const X x;
 }

At the closing brace, we don't "delete" x.  Rather, we "delete"
"const_cast<X> x".  Note that this doesn't give the compiler any powers
the programmer doesn't - he can always add an appropriate const_cast.

BTW, if we're going to argue that deleting an object isn't a const
operation because the object vanishes, why isn't the following legal:

 { const X* x = new X;

  new(static_cast<const void*>x) Y;
 }

In fact, the current line of reasoning would logically allow me to
write:

 f(const X* x)
 { x->~X();
  new(static_cast<const void*>x) X(args);
 }

This would allow me to replace any of X's fields that were accessible
through a constructor for X.  Sure, I could have done the same with a
const_cast - but the whole point of const_cast is that it makes it
obvious where I'm deliberately circumventing the type system. This code
has no const_cast's - or would, if the same logic were applied to
placement new as has been applied to destructors and delete.

       -- 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/04/05
Raw View
In article <memo.19990402092914.51951B@btinternet.com>,
  brangdon@cix.co.uk wrote:
> kuyper@wizard.net (James Kuyper) wrote:
> > 'const' inhibits operations that change the value of the object; it has
> > no relevance to operations that cause the object to cease to exist. If
> > it did, then logically it should also prohibit operations that bring
> > them into existence.
>
> I don't see how that follows. How can something that doesn't exist be
> const?
That was exactly James' point.

The point in question is, are you allowed to delete a const pointer?  Certain
compilers will not let you do this:
void f()
{
   const T *t=new T; // assume T is defined
   //...
   delete t;
}

because these compilers are (incorrectly) looking at it from the point of
view of "Deleting a const object is an attempt to modify it."  Well, from
that point of view, then *creating* a const object (or, shall we say, an
object that will be const) should also be disallowed because you are
attempting to modify a constant object.  Therefore, by this reasoning, you
can neither create nor destroy a constant object - which is clearly not the
intent of 'const'.

Jim
Note to recruitment agencies:  I will not refer my friends or colleagues
to you nor do I want to use your services to find me a job.  I stop
reading unsolicited email as soon as I determine it is job-recruitment

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ 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/04/05
Raw View
Jim Hyslop <jim.hyslop@leitch.com> wrote in message
news:7eaq69$ll$1@nnrp1.dejanews.com...
> because these compilers are (incorrectly) looking at it from the point of
> view of "Deleting a const object is an attempt to modify it."  Well, from
> that point of view, then *creating* a const object (or, shall we say, an
> object that will be const) should also be disallowed because you are
> attempting to modify a constant object.  Therefore, by this reasoning, you
> can neither create nor destroy a constant object - which is clearly not
the
> intent of 'const'.

I disagree here. IMHO it's not a logical reasoning. Creating an object is
fundamentally different from destroying one. The difference is that at the
starting point of destruction you have an object, whereas when you start to
build one you don't have anything. (That's why you can have a virtual
destructor but not a virtual constructor, btw).

The debate remains open...

Andrei
Note to recruitment agencies: Look what you all have done! You forced Jim to
write a very detailed trailer that's not separated from the message itself
by any visible means (dashes etc.). Because of you, darned recruitment
agencies, I bump into his trailer whenever I am reading one of his postings.




[ 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: "Matt Seitz" <mseitz@meridian-data.com>
Date: 1999/04/05
Raw View

Marc Girod wrote in message <1ywvzrrup7.fsf@mahtan.ntc.nokia.com>...
>As soon as somebody disagrees
>with an assertion, the others should stop pretending it is common
>sense. Isn't _that_ common sense? :-)


I don't think so.  "Common sense" in my mind does not equal "universal
acceptance".  To me, describing something as common sense means that a
majority of people would agree with it without further debate.

I think it would be asking too much to require that no one, ever be
surprised by how a C++ feature works.  That is a worthwhile goal, but not
always acheivable.  When evaluating C++ features, the relevant questions
are:

1.  Would most C++ users expect the feature to work the way it does?  In
this case, would most C++ users expect to be able to delete a pointer to a
const object?
2.  Does the potential misunderstanding of C++ users outweigh the benefits
of this feature?




[ 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/04/05
Raw View
In article <3F3O2.13891$mv3.864718@newscene.newscene.com>,
Al Stevens <alstevens@midifitz.com> wrote:

> Someone said elsewhere that this subject was hotly debated in full
> committee. Perhaps the members who participated can present those arguments
> here for the rest of us

OK, here's one.


template<class T> void f(T* tp)
{
 T t = *tp;
}

template<class T> void g(T* tp)
{
 T* tp1 = new T(*tp);
 delete tp1;
}

int main()
{
 const int x = 3;

 f(&x);
 g(&x);
}

If you allow the call to f, why not the call to g?  They do the same thing.
--
    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: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 1999/04/05
Raw View
Andrew Koenig wrote in message ...
[snip, please see the referring post for the code]
>If you allow the call to f, why not the call to g?  They do the same
thing.


I don't think they do quite the same thing.
While destroying statically-allocated objects follows known rules,
destroying others is to be decided by the users.

Thinking of this, I would hardly say f() and g() do the same thing.
f() builds an automatic variable whose existence obeys rigorous rules,
and g() build a dynamic variable which just *happens* to be destroyed
in the same scope - it could be not. This is a big a difference to me.

The variable in f() is destroyed by the compiler, and the one in g()
is destroyed by the programmer. (There are anyway many things that are
allowed to the compiler and not allowed to the user.) This is another
important difference to me.

But what determined me to think that it's not actually a good rule is
that when we pass const objects to functions we don't expect to be
able to detect any change in the object incurred by that function. And
crash following unwitting destruction *is* a detectable change.

Andrei



[ 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/04/06
Raw View
bvisscher@mindspring.com (Bruce Visscher) wrote:
> So you're proposing that objects with destructors can't be const?

Not at all. To begin with I wasn't even suggesting that the rule was
wrong, really. I'm questioning that it is "common sense". There are plenty
of C++ rules that are (in my view) right but which are not obvious; which
depend on subtle interactions or deep experience.



Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/04/06
Raw View
>The result is that a whole class of preventable errors are
>not caught by a standard-conforming compiler, and it is now
>impractical to warn about them either.  This is unfortunate.
>C++ does show some evidence of "design by committee", and this
>is one of the more egregious, because it is so gratuitous.

There's the rub. The destructor can, in the service of destruction, call
non-const functions of other classes and do non-const things outside its own
realm. But, as others have pointed out, that's true too for the automatic
destruction of local const objects, and externs, too. I don't see the
difference. Perhaps someone can explain the philosophical difference between
destroying objects with delete and automatic destruction other than just
saying that there is one.

Following your argument, one could conclude that a destructor, even for a
non-const object, should not be permitted to mess with const data members of
its own class.

I keep hearing here from some that deleting a pointer to a const object
should not be permitted, but I do not hear any compelling reason why. If
cfront and other pre-standard compilers did not permit it, there must have
been a good reason, and surely there was a lot of code that did not need it.
Would someone provide the reason, something beyond simply stating that const
objects must never be changed?

This discussion explains why I occasionally had to remove some consts from
VC++ programs. I thought it was a compiler bug. Turns out it wasn't then but
now 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: James Kuyper <kuyper@wizard.net>
Date: 1999/04/06
Raw View
Matt Seitz wrote:
>
> Marc Girod wrote in message <1ywvzrrup7.fsf@mahtan.ntc.nokia.com>...
> >As soon as somebody disagrees
> >with an assertion, the others should stop pretending it is common
> >sense. Isn't _that_ common sense? :-)
>
> I don't think so.  "Common sense" in my mind does not equal "universal
> acceptance".  To me, describing something as common sense means that a
> majority of people would agree with it without further debate.

"Common sense" is a term with no testable meaning. Arguments based upon
so-called "common sense" are, in my experience, cover-ups for the fact
that someone has been believing something without bothering to ask
themselves why it should be believed (possibly because the reason is so
obvious that it needn't be asked, but that's usually NOT the case for
any idea that someone actually disagrees with).

Let's drop the question of "common sense", and get back to testable
issues, such as what the standard says, what works, what causes
problems, and what's been widely implemented, and what do the majority
of users expect (regardless of whether or not that expectation is
"common sense").
---
[ 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/04/06
Raw View
Marc Girod wrote in message <1ywvzrrup7.fsf@mahtan.ntc.nokia.com>...
>This said, shouldn't we stop speaking of design bug in the language?
>This doesn't seem more justified that the "common sense" position...

Here's the opinion of someone without any prejudice. I humbly confess
that initially (when this thread started), I wasn't aware of the whole
problem at all. It just didn't occur to me. I've read all the postings
carefully and in the end I was convinced by Dave Harris' argument.

For judging what would be more appropriate, let's think: what's const
all about? Now seriously, what do we expect from const? We all know
const is a great design tool: it helps the compiler to check important
invariants. It automates part of the design validation. (You know,
when you put const to a method and you get compiler errors until in
the end you likely discover a flaw in your design...)

To me at least, when I see a function/method taking a const argument,
this means something very important: that function will leave the
object in the same logical state. I shouldn't be able to detect any
change in that object after calling a const function on it. (In
particular, I should be able to call a const function for an
indefinite number of times against the same object without affecting
it at all.) This is something very important to me. It's a deep
philosophical point.

void f(const Something *);

void g(Something *p);
{
    p->foo();
    f(p); // I shouldn't see *p changing after calling f
    p->bar(); // detectable change (crash) if f deletes the object
}

Now suddenly I discover that a function taking a pointer to a constant
object can very easily nuke the object altogether, although
significant efforts have been made by language designers to prevent
the function from changing the object. The assumption about constness
I made so far have fallen. I think this is a loophole in the type
system.

I think this is not okay at all. At least I strongly disagree with
those who say it's common sense. I am avid of hearing the arguments
that determined the commitee to allow this behavior.

Andrei
---
[ 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: Jochen Klein <Jochen.Klein@gmx.de>
Date: 1999/04/06
Raw View
Barry Margolin wrote:
>
> In article <3703AFD8.FFA7F7E8@gmx.de>,
> Jochen Klein  <Jochen.Klein@gmx.de> wrote:
> >Sorry, but constness is a property of the pointer to the object, not of
> >the object itself!
>
> That may be what the Subject line says, but read what he wrote in the
> message, which was of the form:
>
> const T * p = new T;
>
> That's a mutable pointer to a const object.  A const pointer would be:
>
> T * const p = new T;
>

Still:

      T * p = new T ;
const T * cp = p ;

My point is, that one cannot say the object (*cp) is const. The only
thing stated is, that the object cannot be modified using the cp
pointer. There is no problem in having a coule of pointes to the same
object with different cv-qualifiers.
In that respect constness is not an attribute of the object, but of the
pointer to that object. So

const T * p = new T ;

is not creating a const object. It is creating a non-const object an a
pointer to that object is then assigned to a pointer-to-const-object.

Jochen


[ 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/04/06
Raw View
"Al Stevens" <alstevens@midifitz.com> writes:

>I keep hearing here from some that deleting a pointer to a const object
>should not be permitted, but I do not hear any compelling reason why. If
>cfront and other pre-standard compilers did not permit it, there must have
>been a good reason, and surely there was a lot of code that did not need it.
>Would someone provide the reason, something beyond simply stating that const
>objects must never be changed?

>This discussion explains why I occasionally had to remove some consts from
>VC++ programs. I thought it was a compiler bug. Turns out it wasn't then but
>now it is.

That's it in a nutshell.

You'd like to create a const object on the heap. You'd also like
to delete it eventually. With the old rule, you needed a cast. The
formal rule says the results of casting away const and modifying
the object are undefined. That's a pretty sorry state of affairs
in my view, especially contrasted with the complete lack of
any comparable difficulty for auto or static objects.

--
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: David R Tribble <dtribble@technologist.com>
Date: 1999/04/06
Raw View
Jochen Klein  <Jochen.Klein@gmx.de> wrote:
>> Sorry, but constness is a property of the pointer to the object, not
>> of the object itself!

Barry Margolin wrote:
> That may be what the Subject line says, but read what he wrote in the
> message, which was of the form:
>
>    const T * p = new T;
>
> That's a mutable pointer to a const object.  A const pointer would be:
>
>    T * const p = new T;

True enough, but Jochen has a good point to make, which is subtle
and not easy to put into words.  Constness is indeed an aspect of
the pointer to an object, since it prohibits modifying accesses to
the object made through the pointer.  However, this aspect should
not be confused with the constness of a const pointer ('T *const'),
which is indeed a property of the pointer (which prohibits modifying
the pointer itself), but is something altogether different.

Jochen was trying to make the point that declaring a pointed-to
object as const says more about the operations on the pointer to
the object than the object itself.  Consider, for example, why we
declare function arguments as const pointers; most of the time
it's not because the addresses we pass to the functions are
addresses of const objects, but because we want the functions to
act as if they are const objects so that they can't modify the
objects.  In these cases, we're not dealing with const objects at
all, but we are forcing a constness aspect onto the pointers to
those objects.

(To distinguish the "const pointer" idea from the "pointer to const
object" idea, I use the term "property" for the first and "aspect"
for the second.)

Also consider the difference between a 'T*' pointer and a 'const T*'
pointer.  The only real difference between these types is that the
set of operations allowed on the second type is more limited than
those allowed on the first.  This lends credence to Jochen's point
that the 'const' is an aspect of a pointer and not an aspect of the
object it points to.

Note that this "pointer constness" apsect only applies to pointers
and how they are used, and is distinct from the idea of const
objects (such as static const variables).

-- David R. Tribble, dtribble@technologist.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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/04/06
Raw View
Al Stevens <alstevens@midifitz.com> wrote:

> Someone said elsewhere that this subject was hotly debated in full
> committee. Perhaps the members who participated can present those arguments
> here for the rest of us

There's an analogy with the Unix permissions system.
It may come as a surprise to some that under Unix,
a user can delete a file to which they have only read-only
access permission; they just need write access to the directory.
But once you understand how the Unix file system works, then this
seems quite natural, and right.  Indeed it would be silly if you
could make a link to a read-only file and then not be able to delete
the link.  So the idea of being able to delete something even though
it is "read-only" may indeed be common sense, to experienced Unix hackers ;-)

Of course, Unix's file permissions system is not necessarily the best,
and is by no means the most expressive.  Some other operating systems
have more fine-grained capability-based security systems.  Along these
lines, it might be nice if C++ had a more fine-grained capability system
that had enough states to distinguish between write permission and
delete/destroy permission.  But unfortunately -- or perhaps fortunately? --
it doesn't; and what with C++ being rather complex already, no-one on the
committee wanted to extend C++ in that fashion.

So we have two fundamentally different capabilities -- write permission
and delete/destroy permission -- but only a single bit (`const' or not)
to represent them in.  We were thus left with the choice of either
trying to make a single keyword do double-duty by squeezing these two
capabilities into one, or of simply using const for write permission
and acknowledging that C++ had compile-time support for enforcing write
permission but no compile-time support for enforcing object lifetimes.
The old C/C++ style of trying to get the most out of every keyword had
gone somewhat out of fashion by this stage... although I notice that
C9X has added yet _another_ meaning for the keyword `static', so
perhaps it is experiencing a renaissance ;-).  But anyway, if you agree
that these capabilities are fundamentally different, then you'll
probably agree that using `const' for both would be a mistake.  And
there are some important differences: for the most part, C++ does give
you compile-time protection against writing `const' objects, but in
general with object lifetimes there are no simple guarantees; even if
we prohibited deleting pointers to `const', there would still be no
easy way to protect against objects going out of scope.

Some argued that we should stick with the old Cfront rule, which was
that deleting a pointer to const was not allowed, since that was the
"status quo".  But the counter-argument was that Cfront and other C++
compilers had always allow explicit destructor calls via const lvalues:

 void f(const T *p) {
  p->~T();
 }

So the status quo was really quite inconsistent.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.


[ 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/04/06
Raw View
Steve Clamage<clamage@eng.sun.com> wrote:
>
>You'd like to create a const object on the heap. You'd also like
>to delete it eventually. With the old rule, you needed a cast. The
>formal rule says the results of casting away const and modifying
>the object are undefined. That's a pretty sorry state of affairs
>in my view, especially contrasted with the complete lack of
>any comparable difficulty for auto or static objects.

Nonsense.

There is no such thing as a const object on the heap.  There are
only pointers-to-const resulting from conversion from the pointers
to the non-const objects on the heap.  (Only static and auto objects
can actually be const.)  Casting away const on a pointer to an
actually non-const object is well-defined, and that's what we're
talking about.

The comparison to auto const objects is argument by analogy
(and thus fraudulent) as explained and exemplified elsewhere.
It was arguments of the caliber of Steve's, and Andrew's (quoted
in my other posting), and none better, that persuaded the committee
to change the rule and introduce this design flaw.

--
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/04/06
Raw View
>The variable in f() is destroyed by the compiler, and the one in g()
>is destroyed by the programmer. (There are anyway many things that are
>allowed to the compiler and not allowed to the user.) This is another
>important difference to me.


This characterization of the difference between automatic destruction and
explicit destruction with delete makes a strong argument against the new
behavior as defined in the standard. I am curious; how close was the vote on
this issue?




[ 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/04/06
Raw View
In article <7ebg5j$gpu8@news.okidata.com>,
Andrei Alexandrescu <andrewalex@hotmail.com> wrote:

> This is something very important to me. It's a deep
> philosophical point.

> void f(const Something *);

> void g(Something *p);
> {
>     p->foo();
>     f(p); // I shouldn't see *p changing after calling f
>     p->bar(); // detectable change (crash) if f deletes the object
> }

But there is no such guarantee anyway, even if the type system is
completely strict about const, because f might have a non-const alias
to p that it obtained from another source.
--
    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: "Matt Seitz" <mseitz@meridian-data.com>
Date: 1999/04/06
Raw View
Steve Clamage wrote in message <7edb2v$71o$1@engnews1.eng.sun.com>...
>That's it in a nutshell.
>
>You'd like to create a const object on the heap. You'd also like
>to delete it eventually. With the old rule, you needed a cast. The
>formal rule says the results of casting away const and modifying
>the object are undefined. That's a pretty sorry state of affairs
>in my view, especially contrasted with the complete lack of
>any comparable difficulty for auto or static objects.

Ah, now I see both sides of the argument.

Side 1:  The following should not be allowed:

void foo(Bar const * bar){
    delete bar;
}

Rationale:  Declaring an argument as pointer to const is generally
understood as meaning the function will not modify the argument.  By
allowing delete to be called, we are allowing the function to modify the
argument.

Side 2:  The following should be allowed:

void foo(){
    Bar const * bar = new Bar;
    delete bar;
}

Rationale:  See Steve Clamage's note above.

Is there any way to make both sides happy?  This sounds vaguely reminiscent
of the wrangling over auto_ptr, where one sided wanted to allow auto_ptr
function returns, but the other did not want to allow copying const
auto_ptr.  The committee came up with a solution in that case that made both
sides happy.  Perhaps we can find a similar solution here to make both sides
happy?
---
[ 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/04/06
Raw View
>I keep hearing here from some that deleting a pointer to a const object
>should not be permitted, but I do not hear any compelling reason why.

And now I have heard such an argument. See my response to Andrei's post.
This is one of those issues where both sides display such strong merit that
unanimous consensus might never be realized.
---
[ 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: "AllanW {formerly AllanW@my-dejanews.com}" <allan_w@my-dejanews.com>
Date: 1999/04/07
Raw View

> David Harmon <source@netcom.com> wrote in message
> news:371beff6.161521780@nntp.ix.netcom.com...
> > Still, maybe we need:
> >
> >    class foo {
> >    public:
> >        ~foo();
> >        ~foo() const;

In article <7e320f$5cd2@news.okidata.com>,
  "Andrei Alexandrescu" <andrewalex@hotmail.com> wrote:
> I felt once in need to be able to distinguish at construction time whether
> an object is const or not. I'd like to be able to define a const constructor
> and a const destructor. They would be able to perform non-const operations,
> though. So that would be an exception to const methods. But ctors are
> special methods anyway.

Why stop there?

    class foo {
    public:
        // Note: matching destructors not shown, use your imagination

        // Can use const for objects declared const
        foo();        // "Default" if no other ctor applies
        foo() const;  // const foo f;

        // Can use to discover WHERE object was built
        foo() auto;   // void bar() { foo f; }
        foo() static; // void baz() { static foo f; }
        foo() new;    // foo *pFoo = new foo;
        foo() new(void*); // foo *pFoo = new(placement) foo; //(1)

        // Can use const in combination with new or auto:
        foo() new const; // const foo*pFoo = new const foo;
    };

Is this enough? Some people would think so, I suppose, but they've never
tried to build robust business applications under a deadline. For these
next suggestions, I don't think that the syntax is at all obvious. But
that isn't important. The point is, if we're going to be productive then
we absolutely MUST have SOME way to determine:
   **** which level the new object is at! i.e.
       -- for an auto variable, was it at function scope or was it
          part of a compound-statement, or part of an if- while-
          or for-statement? What level of braces?
             void bletch() { foo f;  // This is at level 0
                for (foo f; 0; )     // This is at level 1
                   { foo f; }        // This is at level 2
             }
       -- for a static variable, was it at file scope or inside a
          function? Which file and/or which function?
       -- for a global variable, is it truely global, or was it
          instanciated in a namespace? If so, which one?
       -- For an array element, what's the index number(s) and/or
          what is the address of the first element in the array?
          Also, we should have the ability to alter the array size
          while the array is still being constructed; this will
          allow us to prevent wasted space.
   **** if an object is being destructed in a normal way, in a
          catch() block, due to program termination, or due to
          imminent computer shutdown or power loss. In the latter
          case, there should be a way to delay that at least 30
          minutes.
   **** for virtual-memory systems, we should be able to declare a
          callback to be used when the object is paged in or out of
          the working set.
   **** we should be able to define const_cast<> on a per-class
          basis so that we can control non-const access to const
          objects.
   **** As was mentioned in another thread, friend / public /
          protected / private access is simply too coarse -- we
          either have full security or none at all! We could solve
          this by creating something like the ACL (Access Control List)
          mechanism used in so many operating systems (VAX/VMS and
          Windows NT, to name two). Each sub-object would have an ACL
          specifying which other objects could access them, and what
          accesses were permitted (i.e. read, write, call, call
          debugging functions, take address, grant friendship to
          others). A special access called "security" would indicate
          that all attempted access (successful or not) would also
          write to a log file...

We simply can't be expected to get our work done unless we have
these tools available!



(1) If we have time, we can extend this to allow the placement-new
    constructor to determine *all* of the placement arguments (instead
    of just the resulting address available in "this"):

        foo:foo(int d, int e) new(int a, int b, void*c) {
            #ifdef DEBUG
                std::cout << "new(" << a << ", " << b << ", " << c
                    << ") foo(" << d << ", " << e << ")" << std::endl;
            #endif
            // ...
        }

----
Allan_W@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ 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/04/07
Raw View
clamage@eng.sun.com (Steve Clamage) wrote:
> You'd like to create a const object on the heap. You'd also like
> to delete it eventually. With the old rule, you needed a cast.

That simply isn't true. With the old rule you needed to preserve the type
of the object. That could be done with a wrapper class (or by adding an
extra pointer). The wrapper class would a type-safe template, ideally part
of the STD along with std::auto_ptr<>, and it would be trivially optimised
away so that there would be no run-time overhead at all. No casts would be
necessary.


> The formal rule says the results of casting away const and modifying
> the object are undefined.

Incidently, I don't think that is true if the object was not const to
begin with. The result of (new Object) is not const. The meaning of that
expression does not depend on context; that is, it does not change if the
value is assigned to a const pointer.

  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/04/07
Raw View
In article <%KqO2.6594$3W1.302514@newscene.newscene.com>,
Al Stevens <alstevens@midifitz.com> wrote:

> This characterization of the difference between automatic destruction and
> explicit destruction with delete makes a strong argument against the new
> behavior as defined in the standard. I am curious; how close was the vote on
> this issue?

I'm afraid I don't remember -- but there are few close votes in
the committee.  We tend to argue about a topic until the vote
is clearly going to be lopsided.
--
    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: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/04/07
Raw View
Marc Girod <girod@stybba.ntc.nokia.com> wrote:
>>>>>> "NM" == Nathan Myers <ncm@nospam.cantrip.org> writes:
>Anyway, what's wrong with Andrew Koenig's point that we have anyway to
>accept that local variables (const or not) are indeed deallocated, and
>better so?

--
>Andrew Koenig wrote
>>> The destructor changes the state of the object, can and probably does
>>> overwrite its bytes with garbage etc. In what way is it a const operation?
>>In the same way that deallocating a local variable is a const operation.
--
>This said, shouldn't we stop speaking of design bug in the language?

No.  It's a design bug.  The contrary argument quoted above is
argument by analogy, and thereby fraudulent.  Nonetheless, many
(enough) on the committee found it persuasive, to our detriment
and their shame.

A local const variable is being destroyed with full knowledge of its
creator, in the same context where it was created, and where it is
lexically impossible to try to continue using it.  Destruction in
some random other context is in no wise equivalent.  For an example,
consider:

  void g(T const*);
  void f() { const T t; g(&t); }

Without studying the implementation of g, we cannot tell anything about
the safety of f, purely because of this one language design error.

In place of a language rule, we are left with a much weaker
coding-style rule: "it's a mistake to delete a pointer to a
const object you are passed, because the caller might still
be using the object."

--
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/04/07
Raw View
Fergus Henderson<fjh@cs.mu.OZ.AU> wrote:
>Al Stevens <alstevens@midifitz.com> wrote:
>> Someone said elsewhere that this subject was hotly debated in full
>> committee. Perhaps the members who participated can present those
>> arguments here for the rest of us
>
>There's an analogy with the Unix permissions system. ...
>a user can delete a file to which they have only read-only
>access permission; they just need write access to the directory.
>But once you understand how the Unix file system works, then this
>seems quite natural, and right.  Indeed it would be silly if you
>could make a link to a read-only file and then not be able to delete
>the link.  So the idea of being able to delete something even though
>it is "read-only" may indeed be common sense, to experienced Unix
>hackers ;-)

This is another fraudulent argument-by-analogy.  (It _did_ come
up in the committee discussion, IIRC, and was apparently persuasive
to some, to my disbelief.)  "Objects" in the Unix file system are
garbage-collected, and "unlink" there is equivalent to zeroing out
a pointer to garbage-collected memory, not explicitly destroying
what it points to.

If we had a std::counted_pointer<> I would expect it to cast away
const and delete the object when the count went to zero; but that
is completely orthogonal to the semantics we are talking about here.

>So we have two fundamentally different capabilities -- write permission
>and delete/destroy permission -- but only a single bit (`const' or not)
>to represent them in.  We were thus left with the choice of either
>trying to make a single keyword do double-duty by squeezing these two
>capabilities into one, or of simply using const for write permission
>and acknowledging that C++ had compile-time support for enforcing write
>permission but no compile-time support for enforcing object lifetimes.

Thus the fraudulent analogy leads astray another who is well-equipped
_and_ employed to reason better.

>Some argued that we should stick with the old Cfront rule, which was
>that deleting a pointer to const was not allowed, since that was the
>"status quo".  But the counter-argument was that Cfront and other C++
>compilers had always allow explicit destructor calls via const lvalues:
>
> void f(const T *p) { p->~T(); }
>
>So the status quo was really quite inconsistent.

Finding one mistake is not a reason to add a second mistake.

We're stuck with the mistake, but we should exercise enough
intellectual honesty to recognize and acknowledge it.  We all
know C++ isn't perfect, and this is one of the places where it
isn't.  What's unfortunate is that it was correct in Cfront,
and got 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: Egerton Nick Vg23 X3213 <egertonn@mcd.alcatel.be>
Date: 1999/04/07
Raw View
--------------D56E70F57B95B083D34230E0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

For those interested the standard is pretty explicit. In Section 5.3.5
clause 2 note 2 of ISO/IEC 14882 (first edition 1998-09-01) page 81
it states:

"Note: a pointer to a const type can be an operand to a delete-expression;
it is not necessary to cast away the constness of the pointer expression
before it is used as the operand of the delete-expression."


Regards,

Nick Egerton



--------------D56E70F57B95B083D34230E0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
For those interested the standard is pretty explicit. In Section 5.3.5
<br>clause 2 note 2 of ISO/IEC 14882 (first edition 1998-09-01) page 81
<br>it states:
<p><b>"Note: a pointer to a const type can be an operand to a delete-expression;</b>
<br><b>it is not necessary to cast away the constness of the pointer expression</b>
<br><b>before it is used as the operand of the delete-expression."</b>
<br>&nbsp;
<p>Regards,
<p>Nick Egerton
<br>&nbsp;
<br>&nbsp;</html>

--------------D56E70F57B95B083D34230E0--
---
[ 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: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 1999/04/07
Raw View
>>>>> "NM" == Nathan Myers <ncm@nospam.cantrip.org> writes:

NM> No.  It's a design bug.  The contrary argument quoted above is
NM> argument by analogy, and thereby fraudulent.

Hmm. I don't believe that an argument by analogy is _thereby_
fradulent.
It would be if it pretended to be something else, e.g. a proof.

Arguments by analogy are valuable by themselves, as such: they don't
need to pretend to act in any other way. Analogy is the basis for what
we use to call "orthogonality".

For complex arguments, there is usually no proof. At best, if they are
expressed formally enough, there can be a proof that they are _wrong_.

NM> For an example, consider:

NM>   void g(T const*);
NM>   void f() { const T t; g(&t); }

NM> Without studying the implementation of g, we cannot tell anything about
NM> the safety of f, purely because of this one language design error.

Indeed, pointers (const or not) are too weak for that.
For this type of high-level semantics (i.e. for interfaces), one
should use something like reference counted smart pointers.

Again, I wouldn't blame the language...

Best Regards!
Marc

--
Marc Girod                Hiomo 5/1          Voice:  +358-9-511 23746
Nokia Telecommunications  P.O. Box 320       Mobile: +358-40-569 7954
NWS/NMS/NMS for Data      00045 NOKIA Group  Fax:    +358-9-511 23580
                          Finland            marc.girod@ntc.nokia.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: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1999/04/07
Raw View
On 5 Apr 1999 21:11:24 GMT, Andrew Koenig <ark@research.att.com> wrote:

>template<class T> void f(T* tp) { T t = *tp; }
>template<class T> void g(T* tp) { T* tp1 = new T(*tp); delete tp1; }

Indeed, f(T*) and g(T*) do the same thing.

>int main()
>{
> const int x = 3;
>
> f(&x);
> g(&x);
>}
>
>If you allow the call to f, why not the call to g?  They do the same thing.

>From one point of view, f(T*) and g(T*) do the same thing.  So if
f(T*) is legal, g(T*) should be too.

>From another point of view, the way f(T*) and g(T*) do what they
do is different.  So the fact that f(T*) is legal does not mean that
g(T*) should be legal.

In the end, I prefer this rule,
   int const * i=new int(0);
   delete i; // error: can't delete pointer to const
This rule makes some sense, but it doesn't make 100% sense.  But because
the rule makes C++ just a little safer, and because the alternative
   delete const_cast<int*>(i);
is not that difficult to deal with, I like the rule!

--
----------------------------------
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: scorp@btinternet.com (Dave Harris)
Date: 1999/04/07
Raw View
jim.hyslop@leitch.com (Jim Hyslop) wrote:
> Well, from that point of view, then *creating* a const object (or,
> shall we say, an object that will be const) should also be
> disallowed because you are attempting to modify a constant object.

But that is not attempting to modify a const object at all. It is
attempting to modify an object that will become const later. Your
situation is analogous to:

    Object *pv = new Object;
    pv->nonConstMethod();   // Legal?
    const Object *pc = pv;

An object does not become const until its constructor is finished.

  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/04/07
Raw View
alstevens@midifitz.com (Al Stevens) wrote:
> Perhaps someone can explain the philosophical difference between
> destroying objects with delete and automatic destruction other than just
> saying that there is one.

One is done by the compiler and the other by the programmer. When the
compiler does it, it enforces certain rules. For example, you cannot
delete something you did not create. With the pointer version, the
restrictions are not enforced.


> I keep hearing here from some that deleting a pointer to a const object
> should not be permitted, but I do not hear any compelling reason why.

Consider a function whose prototype is:

    void proc( const Object *pObject );

Should this function be allowed to delete its argument? This is the key
question.

I think it shouldn't. For me this is so obvious that I have trouble
explaining it. It's what const is *for*. The declaration of the function
is saying that (aliases aside) it has no logical effect on its argument.
Destruction is a major effect.

To me this really does seem like a big hole in the type system. It negates
the value of having const if const objects can be deleted. I am left with
very few worthwhile guarantees over the behaviour of functions like the
above. The "const" in the declaration tells me nothing useful.

----
The main motivation for allowing it seems to be cases like:

    void proc() {
        const Object *pObject = new Object;
        //...
        delete pObject;
    }

where we are imitating auto scope. Pragmatically, this is a rather weak
argument. We can deal with it by using a wrapper class similar to
auto_ptr<>. To me the case is similar to:

    void proc() {
        Base *pBase = new Derived;
        pBase->derivedMethod(); // Compile error.
    }

We correctly forbid this even though we allow:

    void proc() {
        Derived *pDerived = new Derived;
        pDerived->derivedMethod(); // OK!
    }

The analogy is that in the first two cases we have "lost" the exact type
of the object - we've assigned a non-const to a const, or a Derived to a
Base. In both cases we can fix the problem by preserving the exact type.
It's a non-problem, not worth adjusting the type-system for.

  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: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1999/04/07
Raw View
On 05 Apr 99 18:04:40 GMT, Al Stevens <alstevens@midifitz.com> wrote:
>Siemel Naran wrote in message ...

>>The destructor calls a non-const member function.  Now a program,

>The constructor, too, can call a non-const member function and can
>initialize const data members. I doubt that anyone would argue that the
>constructor should not be permitted to act upon non-const members for a
>const object.
>
>Construction and destruction are, in my view, separate from the state of an
>object. The analogy to lifetime is flawed. A destroyed object, and
>consequently one under destruction, has no properties of interest to the
>object's users because there is no cadaver to deal with once construction is
>complete. The object simply ceases to be, said cessation being a product of
>the destructor, which needs all necessary privileges to destroy. Otherwise,
>a program could not automatically destroy a const object that was declared
>as auto,  extern or static.

Sounds reasonable.  Nevertheless, all in all, I'm in favor of:
   int const * i=new int(1);
   delete i; // error (but ok in the current rules)
   delete const_cast<int *>(i); // ok
These rules make C++ just a little safer without compromising any other
excellent features of the language, so they're good rules.
And they don't cause too much grief -- instead of "delete t" we know have
to say "delete const_cast<T*>(t)".  A little more typing, but so what?


--
----------------------------------
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: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/04/07
Raw View
>Now suddenly I discover that a function taking a pointer to a constant
>object can very easily nuke the object altogether, although
>significant efforts have been made by language designers to prevent
>the function from changing the object. The assumption about constness
>I made so far have fallen. I think this is a loophole in the type
>system.

This is the most compelling argument I've seen against the behavior that the
standard now permits. The hole, I think, is dug deeper by the (newly
revealed?) anomaly in the language that local and dynamic objects are
destroyed by the same mechanism. That behavior used to seem so symmetrical
and elegant.
---
[ 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 Biggar <jon@floorboard.com>
Date: 1999/04/07
Raw View
Andrei Alexandrescu wrote:

> void f(const Something *);
>
> void g(Something *p);
> {
>     p->foo();
>     f(p); // I shouldn't see *p changing after calling f
>     p->bar(); // detectable change (crash) if f deletes the object
> }
>
> Now suddenly I discover that a function taking a pointer to a constant
> object can very easily nuke the object altogether, although
> significant efforts have been made by language designers to prevent
> the function from changing the object. The assumption about constness
> I made so far have fallen. I think this is a loophole in the type
> system.
>
> I think this is not okay at all. At least I strongly disagree with
> those who say it's common sense. I am avid of hearing the arguments
> that determined the commitee to allow this behavior.

Rewrite the function using a reference instead, which is a better design
practice anyway.

void f (const Something &);

It is common practice to assume that a function that takes a pointer
might change something, where a function that takes a const reference
will not.

I can see your point to a degree, but an C++ programmer worth his salt
when seeing your definition of f() will wonder why it takes a pointer
rather than a reference.

As another point, choosing "simple" names for your example (like f())
tends to obscure the real issue.  A well designed system would not have
a function f() that destroyes the object.  Instead, it would be called
something like
destroy() or complete_work_and_release().  Good naming covers a
multitude of sins.

--
Jon Biggar
Floorboard Software
jon@floorboard.com
jon@biggar.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: Egerton Nick Vg23 X3213 <egertonn@mcd.alcatel.be>
Date: 1999/03/30
Raw View
I apologise in advance for posting this but we do not have a copy of the

C++ standard and I could not find the answer in the FAQ.

Anyway, should the following compile:

main()
{
  const int * ip = new int;
  delete ip;
}

I've used 4 different compilers with different results:
    Sun Workshop C++ 4.2        does not compile
    Microsoft Visual Studio        does not compile
    DEC C++  6.0                          compiles
    GCC 2.8.1                                compiles

I'd just like to know who is right as we are porting from a
DEC to NT (visual studio) environment.

Regards,


Nick Egerton
---
[ 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/03/30
Raw View
Egerton Nick Vg23 X3213 wrote:
>
> I apologise in advance for posting this but we do not have a copy of the
> C++ standard and I could not find the answer in the FAQ.
>
> Anyway, should the following compile:
>
> main()

I am sure you mean int main () !

> {
>   const int * ip = new int;
>   delete ip;
> }

Deleting a const pointer is ok (that's just common
sens anyway).

--

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 Kuyper <kuyper@wizard.net>
Date: 1999/03/30
Raw View
Egerton Nick Vg23 X3213 wrote:
>
> I apologise in advance for posting this but we do not have a copy of the
>
> C++ standard and I could not find the answer in the FAQ.
>
> Anyway, should the following compile:
>
> main()
> {
>   const int * ip = new int;
>   delete ip;
> }
>
> I've used 4 different compilers with different results:
>     Sun Workshop C++ 4.2        does not compile
>     Microsoft Visual Studio        does not compile
>     DEC C++  6.0                          compiles
>     GCC 2.8.1                                compiles
>
> I'd just like to know who is right as we are porting from a
> DEC to NT (visual studio) environment.

Section 5.3.5p2 contains a note which says "a pointer to a const type
can be the operand of a delete-expression: it is not necessary to cast
away the constness (5.2.11) of the pointer expression before it is used
as the operand of the delete-expression."


[ 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: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/03/31
Raw View
In article <37008962.CA6238A2@mcd.alcatel.be>,
  Egerton Nick Vg23 X3213 <egertonn@mcd.alcatel.be> wrote:
> I apologise in advance for posting this but we do not have a copy of the
> C++ standard and I could not find the answer in the FAQ.
>
> Anyway, should the following compile:
>
> main()
> {
>   const int * ip = new int;
>   delete ip;
> }

Yes, this should compile.  The Standard explicitly allows it.  Oh, now where
did that go... Oh, here it is - 12.4/2:  "A constructor can be invoked for a
const, volatile, or const volatile object.... const and volatile semantics
(7.1.5.1) are not applied on an object under destruction."

Granted, that only specifically talks about invoking the destructor, but
that's implicitly what delete does anyway - it invokes the destructor, at
which point the memory no longer holds a valid object, it simply is a block
of raw memory which can be deallocated.

[snip]
> I'd just like to know who is right as we are porting from a
> DEC to NT (visual studio) environment.
I guess you'll have to toss in a const_cast to get it working, until MS gets
around to fixing it.

Jim
Note to recruitment agencies:  I will not refer my friends or colleagues
to you nor do I want to use your services to find me a job.  I stop
reading unsolicited email as soon as I determine it is job-recruitment

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ 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/03/31
Raw View
Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> Deleting a const pointer is ok (that's just common
> sens anyway).

I agree the standard says it is OK. I don't see that it is common sense.
The destructor changes the state of the object, can and probably does
overwrite its bytes with garbage etc. In what way is it a const operation?

  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: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1999/03/31
Raw View
On 31 Mar 1999 16:40:53 GMT, Dave Harris <scorp@btinternet.com> wrote:
>Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:

>> Deleting a const pointer is ok (that's just common
>> sens anyway).

>I agree the standard says it is OK. I don't see that it is common sense.
>The destructor changes the state of the object, can and probably does
>overwrite its bytes with garbage etc. In what way is it a const operation?

To add to your point, consider:
   struct X {
      int x;
      ~X() { non_const_member_function(); }
      void non_const_member_function() { x=0; }
   };
The destructor calls a non-const member function.  Now a program,
   int main() {
      X const * x=new X();
      x->non_const_member_function(); // error
      delete x; // ok!
   }

--
----------------------------------
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: Ron Natalie <ron@sensor.com>
Date: 1999/04/01
Raw View
Dave Harris wrote:
>
> Bonnard.V@wanadoo.fr (Valentin Bonnard) wrote:
> > Deleting a const pointer is ok (that's just common
> > sens anyway).
>
> I agree the standard says it is OK. I don't see that it is common sense.
> The destructor changes the state of the object, can and probably does
> overwrite its bytes with garbage etc. In what way is it a const operation?
>

By your own logic creating it wasn't a const operation
either.  Do you really think it is necessary to force
users to const_cast the operands to new/delete?
---
[ 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              ]