Topic: delete p changes p (Was: delete this in non-static member function - ok?)


Author: "Marco Dalla Gasperina" <marcodg@panmed.com>
Date: 1999/09/17
Raw View

blargg <postmast.root.admi.gov@iname.com> wrote in message
news:user-1709990434330001@aus-as3-095.io.com...
>
> In article <MPG.124b5c3eb3d2752c9896d0@news.teleport.com>,
> smeyers@aristeia.com (Scott Meyers) wrote:

I wrote:

> > > (1) Invalidating the pointer is only applicable in the case
> > >     of the system supplied allocation function.

> I would assume that the above also applies to calling the system-supplied
> deallocation function directly too:

Yes, it was a typo on my part.  I meant "deallocation function" like it
says in the standard.

>
> If this is the case, then it's not even specific to the delete operator at
> all. This indicates to me that the committee's decision was for delete to
> *not* be magic.

Yes!

>                   The deallocation function can be magic because it may
> interact with the MMU in a way that renders any further use of the pointer
> a processor exception (as Andrew Koenig pointed out to me, and I
> elaborated on, in another message).

This is completely true as far as I'm concerned.  But, the interface
to operator delete is defined as:

    void operator delete( void* p ) throw();

It may render p invalid but it cannot by definition, change the
value the caller is using (but can no longer use in a portable
fashion).

I realize that some of this is akin to asking the "tree falling
in the forest" question.  i.e. If you can't look at an object,
does it have a value?  (Obviously, I believe it does.)

<suck up>
But, allow me my 15 minutes in this most respected and scholarly
forum.
</suck up>

> It is reasonable, I think, as one could expect to be able to delete an
> object that uses a custom deallocator, without affecting the pointer used
> in the delete expression:

I believe this to be true, given the pain the standard goes through
to qualify the deallocation function.

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: smeyers@aristeia.com (Scott Meyers)
Date: 1999/09/17
Raw View
I think I owe Marco some my kung fu.  Look again at 5.3.5/4, where I've
emphasized some text:

4 The  cast-expression in a delete-expression shall be evaluated exactly
  once.  IF THE DELETE-EXPRESSION CALLS THE IMPLEMENTATION  DEALLOCATION
  FUNCTION (_basic.stc.dynamic.deallocation_), and if the operand of the
  delete expression is not the null pointer constant,  the  deallocation
  function  will  deallocate  the storage referenced by the pointer thus
  rendering the pointer invalid.  [Note: the value  of  a  pointer  that
  refers to deallocated storage is indeterminate.  ]

(I've actually copied this from CD-2, because my copy of the standard is
still copy-protected, but I'm fairly certain that the wording in the
standard is the same as in CD-2.)  Now look again at Marco's analysis:

> (1) Invalidating the pointer is only applicable in the case
>     of the system supplied allocation function.

I don't like it, but I have to agree that that's what the standard says.
Furthermore, look at the draft text for the paragraph in question from CD-1
(April 1995):

4 It is unspecified whether the deletion of an object changes its value.
  If the expression denoting the object in a delete-expression is a mod
  ifiable  lvalue, any attempt to access its value after the deletion is
  undefined (_basic.stc.dynamic.deallocation_).

Here's it's quite clear that deleting a pointer may change its value.
Sometime between CD-1 and CD-2, then, the wording was changed to eliminate
this explicit claim that deleting a pointer may change its value.  I
conclude that the committees deliberately chose to eliminate the freedom
for a conforming implementation to modify the value of a deleted pointer.
In particular, I believe that a conforming implementation is not -- modulo
the specific case Marco identified -- allowed to "helpfully" set a deleted
pointer to null.

Scott

--
Scott Meyers, Ph.D.                  smeyers@aristeia.com
Software Development Consultant      http://www.aristeia.com/
Visit http://meyerscd.awl.com/ to demo the Effective C++ CD
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/17
Raw View
In article <MPG.124b5c3eb3d2752c9896d0@news.teleport.com>,
smeyers@aristeia.com (Scott Meyers) wrote:

> I think I owe Marco some my kung fu.

:-)

I agree. Marco's point was good.

> Look again at 5.3.5/4, where I've emphasized some text:
>
> 4 The  cast-expression in a delete-expression shall be evaluated exactly
>   once.  IF THE DELETE-EXPRESSION CALLS THE IMPLEMENTATION  DEALLOCATION
>   FUNCTION (_basic.stc.dynamic.deallocation_), and if the operand of the
>   delete expression is not the null pointer constant,  the  deallocation
>   function  will  deallocate  the storage referenced by the pointer thus
>   rendering the pointer invalid.  [Note: the value  of  a  pointer  that
>   refers to deallocated storage is indeterminate.  ]
>
> (I've actually copied this from CD-2, because my copy of the standard is
> still copy-protected, but I'm fairly certain that the wording in the
> standard is the same as in CD-2.)  Now look again at Marco's analysis:
>
> > (1) Invalidating the pointer is only applicable in the case
> >     of the system supplied allocation function.

I would assume that the above also applies to calling the system-supplied
deallocation function directly too:

    void* p = operator new ( 1 );

    operator delete ( p );

    if ( p == 0 ) // undefined

Correct?

If this is the case, then it's not even specific to the delete operator at
all. This indicates to me that the committee's decision was for delete to
*not* be magic. The deallocation function can be magic because it may
interact with the MMU in a way that renders any further use of the pointer
a processor exception (as Andrew Koenig pointed out to me, and I
elaborated on, in another message).

> I don't like it, but I have to agree that that's what the standard says.
> Furthermore, look at the draft text for the paragraph in question from CD-1
> (April 1995):
>
> 4 It is unspecified whether the deletion of an object changes its value.
>   If the expression denoting the object in a delete-expression is a mod
>   ifiable  lvalue, any attempt to access its value after the deletion is
>   undefined (_basic.stc.dynamic.deallocation_).
>
> Here's it's quite clear that deleting a pointer may change its value.

Agreed.

> Sometime between CD-1 and CD-2, then, the wording was changed to eliminate
> this explicit claim that deleting a pointer may change its value.  I
> conclude that the committees deliberately chose to eliminate the freedom
> for a conforming implementation to modify the value of a deleted pointer.

Or perhaps the wording before was really *intended* to cover this specific
case only, and was later corrected to reflect this intention.

It is reasonable, I think, as one could expect to be able to delete an
object that uses a custom deallocator, without affecting the pointer used
in the delete expression:

    struct X {
        void* operator new ( std::size_t );
        void operator delete ( void* );
    };

    void f() {
        X* x = new X;
        delete x;
        if ( x == x_pool_begin ) {
            // ...
        }
    }

There should be no "compiler magic" allowed, other than what is required
to carry out the delete.

> In particular, I believe that a conforming implementation is not -- modulo
> the specific case Marco identified -- allowed to "helpfully" set a deleted
> pointer to null.

I surely hope you quoted "helpfully" to mean it in a sarcastic sense  :-)

Making bugs harder to find is not helpful in my book. Now, if an
implementation set them to some non-null value that caused a processor
exception when accessed, I'd consider that helpful (but only as a
debugging option that could be disabled).


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use 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/09/14
Raw View
In article <37dea03a.0@news.pacifier.com>,
Marco Dalla Gasperina <marcodg@pacifier.com> wrote:
>Suppose I'm working on a non-portable part of a system.

Then it doesn't matter what the standard says.  Even though the standard
might *allow* 'delete p' to set p to NULL, it certainly doesn't *require*
it.  If your compiler does this, it would probably have an option to
disable it (if it doesn't, beg the compiler vendor to add it).  Also, if it
does this, you can always work around it using suitable indirections.
Without excessive overhead that no implementor would consider (except
perhaps in a checkout or teaching compiler), delete can only null out the
lvalue that was used with it.  So you can define a template like:

template <class T> void deleteit(T *p) {
  delete p;
}

Then only the temporary p inside the template function will be nulled,
while the variable you passed should be safe and unchanged.

--
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: "Marco Dalla Gasperina" <marcodg@pacifier.com>
Date: 1999/09/15
Raw View

Barry Margolin <barmar@bbnplanet.com> wrote in message
news:HAyD3.8$zE6.277@burlma1-snr2...
>
> In article <37dea03a.0@news.pacifier.com>,
> Marco Dalla Gasperina <marcodg@pacifier.com> wrote:
> >Suppose I'm working on a non-portable part of a system.
>
> Then it doesn't matter what the standard says.

Yes it does.  Nothing in my code (that I know of) invokes
undefined behavior. In that case the compiler must abide
by what the standard says.

>                                                  Even though the standard
> might *allow* 'delete p' to set p to NULL, it certainly doesn't *require*
> it.

Agreed.  But if my code stops working after I upgrade because
of this, who's fault is it?

Part of what makes C++ fun for me is precisely this bickering over
the language.  Part of it is also disagreeing with people who are
a lot smarter than I am... maybe I'll learn something from them.

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: David R Tribble <david@tribble.com>
Date: 1999/09/14
Raw View
Scott Meyers wrote:
>
> On 08 Sep 99 19:17:00 GMT, Valentin Bonnard wrote:
>> Marco Dalla Gasperina wrote:
>>
>> > Are you saying that the implementation is allowed to change the
>> > value of the pointer deleted?
>>
>> yes
>>
>> Try to prove the contrary !
>
> 5.3.5/4 of the standard reads this way:
>
>   The cast-expression in a delete-expression shall be evaluated
>   exactly once.   If the delete-expression calls the implementation
>   deallocation function (_basic.stc.dynamic.deallocation_), and if
>   the operand of the delete  expression  is not the null pointer
>   constant, the deallocation function will deallocate the storage
>   referenced by  the  pointer  thus rendering  the  pointer invalid.
>   [Note: the value of a pointer that refers to deallocated storage is
>   indeterminate.]
>
> It seems pretty clear to me that the last sentence allows the value of
> a pointer to be changed as a side-effect of deleting the pointer.
> Presumably this includes the "this" pointer.

I'm of the opinion that 'delete' should set the pointer expression to
null (assuming that it's not a const object), and I've said so in the
past.  This would render certain coding practices less unsafe:

    delete p;   // non-const 'p' set to null
    ...
    delete p;   // benign behavior, 'p' is null

As it stands now, such code is ill-behaved, and requires extra care
to make it well-behaved:

    delete p, p = NULL;  // force 'p' to be null
    ...
    delete p;

-- David R. Tribble, david@tribble.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/14
Raw View
David R Tribble wrote:

> I'm of the opinion that 'delete' should set the pointer expression to
> null

giving a false sens of security

You can have a deleter function which does
that anyway:

template <typename T>
void deleter (T*& p)
{
    delete p;
    p = NULL;
}

Also what about delete (some rvalue) ?

> (assuming that it's not a const object),

Once again, constness is irrelevant

--

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: "Marco Dalla Gasperina" <marcodg@pacifier.com>
Date: 1999/09/14
Raw View
David R Tribble <david@tribble.com> wrote in message
news:37DD8A42.90C2DABA@tribble.com...
>
> Scott Meyers wrote:
> > 5.3.5/4 of the standard reads this way:
> >
> >   If the delete-expression calls the implementation
> >   deallocation function (_basic.stc.dynamic.deallocation_), and if
> >   the operand of the delete  expression  is not the null pointer
> >   constant, the deallocation function will deallocate the storage
> >   referenced by  the  pointer  thus rendering  the  pointer invalid.
> >   [Note: the value of a pointer that refers to deallocated storage is
> >   indeterminate.]
> >
> > It seems pretty clear to me that the last sentence allows the value of
> > a pointer to be changed as a side-effect of deleting the pointer.
> > Presumably this includes the "this" pointer.
>
> I'm of the opinion that 'delete' should set the pointer expression to
> null (assuming that it's not a const object), and I've said so in the
> past.  This would render certain coding practices less unsafe:
>

I guess I'm the only person on this group that believes that
the implementation is NOT allowed to touch the pointer on which
delete operator is applied.  Seeing that those who disagree with
me have greater kung fu than I do (Meyers, Koenig, et. al) I feel
somewhat naked, yet...

My reasons are:

(1) Invalidating the pointer is only applicable in the case
    of the system supplied allocation function.  In other words,
    the following is presumably ok:

    /* file1.cpp */
    struct Foo {};
    Foo global_foo;

    void operator delete( void* p ) throw() {}

    /* file2.cpp */
    struct Foo {};
    int main() {
        Foo* p = new Foo;
        delete p;
        if ( p == NULL ) { /* */ }
        return 0;
    }

    I can use the value of p because p has not been invalidated
    and the implementation is not allowed to touch it because I
    have a provided definition for the global deallocation function.

(2) The phrase "rendering the pointer invalid" is only used in
    conjunction with the deallocation function and in particular
    not in association with the delete operator.  The definition
    of the system deallocation function is:

    void operator delete( void* p ) throw( ??? );

    Note that the pointer p is passed by value and therefore, by
    definition, this function cannot modify the argument.

    There is the note: [Note: the value of a pointer that refers to
    deallocated storage is indeterminate.]  But, notes are not
    normative text.  Still what does it mean?

I submit that it means that, portably, you cannot determine
the 'value' of the pointer.  It does not mean that the value
of the pointer can change.  You may ask?  So, if you can't look
at it who cares?  Well, maybe I do.

Suppose I'm working on a non-portable part of a system.  I know
what the representation of pointers is.  32 bits.  No bits that
are "don't care" or specify the type of operand.  In short:
object_representation == value_representation and there are no
two different value representations that have the same value
(add requirements as necessary to make the following function
provide a one->one mapping of pointers to long).

In such a case, I can ascribe a value to a pointer:
template< class T > long val( T** p ) {
    char b[sizeof(T*)];
    memcpy( b, p, sizeof(b) );
    return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
}

For anyone else, this function template is meaningless, but
I don't care.  To me it's useful.  Now,

    long y = val( &p );
    delete p;
    long x = val( &p );

I'll stipulate that even though referencing p after the delete
would be undefined behaviour, anything can happen.  But, I'm
not doing anything undefined.  I've used (documented) knowledge
of the system to my advantage.  I maintain, because of my
reading of the standard, that

    assert( x==y )

must always pass.  No it's not portable but I don't care about
that. But the implementation, given it's pointer representation,
must not allow this assert to fire.  If it does, I file a defect
report against the implementation (they of course laugh at me).

Be gentle with me.

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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/11
Raw View
In article <FHv5yI.CuC@research.att.com>, ark@research.att.com (Andrew
Koenig) wrote:

> In article <user-0909991914590001@as1-dialup-120.io.com>,
> blargg <postmast.root.admi.gov@iname.com> wrote:
>
> >> The point is that after you execute `delete p;'  p has become an
> >> invalid pointer.
> >
> >And any other pointers that come from p, correct?
>
> Correct.
>
> >And if we change this slightly,
>
> >    q = p;
> >    r = p;
> >    delete p;
> >    if ( q == r ) // ...
> >
> >it's still undefined (right?)
> >
> >We didn't even touch p after the delete.
>
> Right.
>
> >What if we changed it to this:
>
> >    q = p;
> >    r = p;
> >    delete q;
> >    if ( p == r ) // ...
> >
> >Does this still invoke undefined behavior in the comparison? In this case,
> >we're copying q and r from p, and deleting q:
> >
> >         .------> q (deleted)
> >    p --<
> >         '------> r
> >
> >Or am I not understanding this and delete can only invalidate the pointer
> >given to it? (which would involve *much* less "voodoo")
>
> No, you're understanding it.

If you call "voodoo" understanding :-)

> There's no voodoo involved.  The intent is to allow implementation on a
> machine that has special hardware registers for addresses, and that does
> hardware address translation and validity checking when you load an
> address into one of those registers.

Ahhh, I see. On the processors I'm familiar with, address translation
occurs on access, instead of load (and there are no special address
registers). But this makes sense, since it may allow more efficient
implementation in hardware. For example, on the PowerPC, address
translation is done in parallel with cache lookup. This takes one cycle in
the best case, when the translation entry is contained in the translation
table cache.

On processors that do address translation on access, this also limits the
number of address bits that can be used to address the primary (on-chip)
cache, unless the implementation allows the cache to become incoherent
when two logical pages map to the same physical page. For example, on the
PowerPC, pages are 4K in size. This leaves 12 bits of the logical address
that aren't translated, and thus can be used for mapping into the primary
cache. The fewer the address bits available, the more associativity is
required for a cache of a given size. This takes more silicon (*some*
associativity is good, but too much can be quite costly in terms of
silicon - consider complete associativity). When the physical address is
known immediately, all the address bits can be used in addressing the
cache, allowing more flexibility in the mapping scheme.

With the implementation you describe, the processor has the physical
address available immediately, so it can be checking the secondary cache
at the same time (which is often? mapped using the physical address), or
even start a bus transaction with main memory. This eliminates the latency
required when the address is kept untranslated. It does require a check
for a page-crossing to be done when changing an address register, but this
can easily be handled with very little extra silicon and no time overhead.

So, to sum this up with an example a memory access sequence using a
processor with special hardware address registers:

    load    a0,<location>   ; perform address translation here
    load    r0,(a0)         ; no address translation needed
    add     a0,r0           ; need to see if a0 crosses page boundary
    load    r0,(a0)         ; no address translation needed

Interesting.

> On such a machine, it is not hard
> to imagine that delete might invalidate the page table entry for the given
> memory location, after which the mere attempt to load a pointer to that
> location into an address register would cause a fault.


Right.

    load    a0,<location>   ; perform address translation
                            ; boom! no table entry


Yes! This makes perfect sense, and is a model I can keep in my head in the
future when considering these issues. No voodoo at all; just consideration
of these architectures in a way that doesn't pose any significant
practical restrictions on programs.

Thanks for explaining this.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Pete Becker <petebecker@acm.org>
Date: 1999/09/09
Raw View
Valentin Bonnard wrote:
>
> Marco Dalla Gasperina wrote:
>
> > Are you saying that the implementation is allowed to change the
> > value of the pointer deleted?
>
> yes
>
> Try to prove the contrary !
>
> If you can't them I can say that it does change the value.
>

To put this a little more formally: see if you can write a valid C++
program that can detect such a change. If you can't detect it, it's
allowed, if for no other reason, by the as-if rule.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.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: "Marco Dalla Gasperina" <marcodg@pacifier.com>
Date: 1999/09/09
Raw View
Scott Meyers <smeyers@aristeia.com> wrote in message
news:MPG.1240e515d4f641d49896cc@news.teleport.com...
> 5.3.5/4 of the standard reads this way:
>
>   The cast-expression in a delete-expression shall be evaluated  exactly
>   once.   If the delete-expression calls the implementation deallocation
>   function (_basic.stc.dynamic.deallocation_), and if the operand of the
>   delete  expression  is not the null pointer constant, the deallocation
>   function will deallocate the storage referenced by  the  pointer  thus
>   rendering  the  pointer  invalid.   [Note: the value of a pointer that
>   refers to deallocated storage is indeterminate.  ]
>
> It seems pretty clear to me that the last sentence allows the value of a
> pointer to be changed as a side-effect of deleting the pointer.

Consider...

void Foo( Bar* p ) {
    Bar* x = p;
    delete p;
    if ( memcmp( &x, &p, sizeof(p) ) == 0 )
        cout << "unchanged\n";
    else
        cout << "changed\n";
}

Can a conforming implementation print "changed" ?

I'm not so certain of Scott's interpretation.  (I'm presuming
he's referring to the 'Note').  'Indeterminate' means that you
cannot determine it's value not and not that the value can change.

What about when the pointer is an expression? eg.

void Baz( Bar* p ) { delete p-1; }
Baz( p+1 );

What about all the other pointers that pointed to the object
that was deleted?  These are all indeterminate, but does that
mean that the bits can flip willy-nilly under the covers?

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: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/09
Raw View
Salters wrote:
>
> Valentin Bonnard wrote:
>
> > Marco Dalla Gasperina wrote:
>
> > > Are you saying that the implementation is allowed to change the
> > > value of the pointer deleted?
>
> > yes
>
> > Try to prove the contrary !
>
> > If you can't them I can say that it does change the value.

> Well, in that case it must be forbidden to delete a const pointer.

No (why ?)

> Since there is no such requirement that I am aware of, I conclude
> that only if delete is overloaded so it takes const pointers and
> non-const pointers, delete will be allowed to do so.

foo(T) and foo(T const) are the _same_ signatures in C++.

Not only you cannot overload this way, but you can't even
have too functions differing on the constness of by-value
arguments:

void foo(int const) {}
void foo(int) {} // ill-formed: redefinition

> Which part of the standard mentions delete ( T * const ) ?

None

--

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/09/09
Raw View
Marco Dalla Gasperina wrote:
...
> What about when the pointer is an expression? eg.
>
> void Baz( Bar* p ) { delete p-1; }
> Baz( p+1 );
>
> What about all the other pointers that pointed to the object
> that was deleted?  These are all indeterminate, but does that
> mean that the bits can flip willy-nilly under the covers?

I wouldn't expect them to do so. However, on many implementations a
pointer's value can be changed without changing the bits that represent
that value.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/10
Raw View
In article <37d7efee.0@news.pacifier.com>, Marco Dalla Gasperina
<marcodg@pacifier.com> writes
>What about all the other pointers that pointed to the object
>that was deleted?  These are all indeterminate, but does that
>mean that the bits can flip willy-nilly under the covers?

Well it does mean that no conforming program can determine that they do
not.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/10
Raw View
"Marco Dalla Gasperina" <marcodg@pacifier.com> writes:
> Consider...
>=20
> void Foo( Bar* p ) {
>     Bar* x =3D p;
>     delete p;
>     if ( memcmp( &x, &p, sizeof(p) ) =3D=3D 0 )
>         cout << "unchanged\n";
>     else
>         cout << "changed\n";
> }
>=20
> Can a conforming implementation print "changed" ?

Yes. According to 3.7.3.2=B64, all pointers into deallocated storage
are invalid, and the result of using an invalid pointer is undefined.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/09/10
Raw View
In article <t7ogfbaix3.fsf@calumny.jyacc.com>,
  Hyman Rosen <hymie@prolifics.com> wrote:
> "Marco Dalla Gasperina" <marcodg@pacifier.com> writes:
> > Consider...
> >
> > void Foo( Bar* p ) {
> >     Bar* x = p;
> >     delete p;
> >     if ( memcmp( &x, &p, sizeof(p) ) == 0 )
> >         cout << "unchanged\n";
> >     else
> >         cout << "changed\n";
> > }
> >
> > Can a conforming implementation print "changed" ?

> Yes. According to 3.7.3.2=B64, all pointers into deallocated storage
> are invalid, and the result of using an invalid pointer is undefined.

But he's not using it.  He's comparing the underlying raw memory.

His actual test is invalid, since a conforming implementation can print
"changed" even without the delete -- without the delete, all that is
required is that the two pointers compare equal, not that a memcmp on
the underlying memory sees equality.  And attempting to use == on a
deleted pointer results in undefined behavior.

A somewhat better test might be:

    void
    foo( Bar* p )
    {
        unsigned char   buf1[ sizeof( Bar* ) ] ;
        memcpy( buf1 , &p , sizeof( Bar* ) ) ;
        delete p ;
        unsigned char   buf2[ sizeof( Bar* ) ] ;
        memcpy( buf2 , &p , sizeof( Bar* ) ) ;
        if ( memcmp( buf1 , buf2 , sizeof( Bar* ) ) == 0 )
            cout << "unchanged\n" ;
        else
            cout << "changed\n" ;
    }

Even then, I'm not 100% sure that the standard makes the guarantee, even
without the delete.

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


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


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/09/10
Raw View
In article <FHt11D.G0t@research.att.com>,
  ark@research.att.com (Andrew Koenig) wrote:

> The point is that after you execute `delete p;'  p has become an
> invalid pointer.  There are very strong restrictions on what you
> can do with such pointers -- in particular, you are not permitted
> even to copy the value of such a pointer,

Except with memcpy, of course.

Which is probably irrelevant to the question at hand, since p==q does
NOT imply memcmp( &p , &q , sizeof( ... ) ) == 0, except for char's and
unsigned char's.

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


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


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/10
Raw View
In article <FHt11D.G0t@research.att.com>, ark@research.att.com (Andrew
Koenig) wrote:

> In article <37D79ACD.8AA70E66@lucent.com>, Salters  <salters@lucent.com>
wrote:
>
> >Valentin Bonnard wrote:
>
> >> Marco Dalla Gasperina wrote:
>
> >> > Are you saying that the implementation is allowed to change the
> >> > value of the pointer deleted?
>
> >> yes
>
> >> Try to prove the contrary !
>
> >> If you can't them I can say that it does change the value.
>
> >Well, in that case it must be forbidden to delete a const pointer.
>
> No, that doesn't follow.
>
> The point is that after you execute `delete p;'  p has become an
> invalid pointer.

And any other pointers that come from p, correct?

>  There are very strong restrictions on what you
> can do with such pointers -- in particular, you are not permitted
> even to copy the value of such a pointer, whether or not you attempt
> to examine the memory to which it points.  As a result, it is
> difficult even to write a well-defined program that detects
> whether or not the value of p has changed.  For example, you
> cannot write
>
>         q = p;
>         delete p;
>         if (p == q) { /* ... */ }
>
> because the result of the comparison p == q is undefined, so an
> implementation is permitted to do absolutely anything, including
> terminating the entire program.

And if we change this slightly,

    q = p;
    r = p;
    delete p;
    if ( q == r ) // ...

it's still undefined (right?)

We didn't even touch p after the delete.

What if we changed it to this:

    q = p;
    r = p;
    delete q;
    if ( p == r ) // ...

Does this still invoke undefined behavior in the comparison? In this case,
we're copying q and r from p, and deleting q:

         .------> q (deleted)
    p --<
         '------> r

Or am I not understanding this and delete can only invalidate the pointer
given to it? (which would involve *much* less "voodoo")


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Salters <salters@lucent.com>
Date: 1999/09/10
Raw View
Andrew Koenig wrote:

> In article <37D79ACD.8AA70E66@lucent.com>, Salters  <salters@lucent.com> wrote:

> >Valentin Bonnard wrote:

> >> Marco Dalla Gasperina wrote:

> >> > Are you saying that the implementation is allowed to change the
> >> > value of the pointer deleted?

> >> yes

> >> Try to prove the contrary !

> >> If you can't them I can say that it does change the value.

> >Well, in that case it must be forbidden to delete a const pointer.

> No, that doesn't follow.

> The point is that after you execute `delete p;'  p has become an
> invalid pointer.  There are very strong restrictions on what you
> can do with such pointers -- in particular, you are not permitted
> even to copy the value of such a pointer, whether or not you attempt
> to examine the memory to which it points.  As a result, it is
> difficult even to write a well-defined program that detects
> whether or not the value of p has changed.  For example, you
> cannot write

>         q = p;
>         delete p;
>         if (p == q) { /* ... */ }

> because the result of the comparison p == q is undefined, so an
> implementation is permitted to do absolutely anything, including
> terminating the entire program.
> --
> Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark

Looking from this side, I'm now inclined to say the question does not
make sense. Since a pointer cannot even be compared to anything, after
it is deleted, how can we say it has a value then? And if it does not
have a value after it is deleted, the question if the value before
deletion is eqaul to the value after deletion is nonsense.

Therefore, whatever an implementation does with _the bits formerly
occupied by_ the pointer is of course up to the implementation,
but these bits should not be interpreted as the value (just as the
bits of the former object now no longer are an object).

I am still wondering about the consequences of this. In particular,
if delete may change its "argument" in such a way that the
"argument" cannot be copied anymore, rvalues are a problem. I'm
not sure if that makes sense, I cannot think up of a case in which
an rvalue is deleted. My problem is that rvalues do not have an
identity : two syntactical equal rvalues may compare equal, but
have a different "identity".

I.e. what is invalidated by delete (p+0); ?  Or is this undefined
behavior (pointer arithmetic on a non-array member)? Can we use
p, as long as we don't try to use (p+0)? I don't think so, but
purely logical I can't prove this.

Michiel Salters


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/11
Raw View
Hyman Rosen wrote:
>=20
> "Marco Dalla Gasperina" <marcodg@pacifier.com> writes:
> > Consider...
> >
> > void Foo( Bar* p ) {
> >     Bar* x =3D p;
> >     delete p;
> >     if ( memcmp( &x, &p, sizeof(p) ) =3D=3D 0 )
> >         cout << "unchanged\n";
> >     else
> >         cout << "changed\n";
> > }
> >
> > Can a conforming implementation print "changed" ?
>=20
> Yes. According to 3.7.3.2=B64, all pointers into deallocated storage
> are invalid, and the result of using an invalid pointer is undefined.

The behaviour is _not_ undefined here; the program=20
can only print unchanged or changed.

--=20

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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/11
Raw View
In article <user-0909991914590001@as1-dialup-120.io.com>, blargg
<postmast.root.admi.gov@iname.com> writes
>
>Does this still invoke undefined behavior in the comparison? In this case,
>we're copying q and r from p, and deleting q:
>
>         .------> q (deleted)
>    p --<
>         '------> r
>
>Or am I not understanding this and delete can only invalidate the pointer
>given to it? (which would involve *much* less "voodoo")

No delete not only invalidates the pointer used by it but all pointers
and iterators into any part of the deleted object.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Salters <salters@lucent.com>
Date: 1999/09/09
Raw View
Valentin Bonnard wrote:

> Marco Dalla Gasperina wrote:

> > Are you saying that the implementation is allowed to change the
> > value of the pointer deleted?

> yes

> Try to prove the contrary !

> If you can't them I can say that it does change the value.

> --

> Valentin Bonnard

Well, in that case it must be forbidden to delete a const pointer.
Since there is no such requirement that I am aware of, I conclude
that only if delete is overloaded so it takes const pointers and
non-const pointers, delete will be allowed to do so.

Which part of the standard mentions delete ( T * const ) ?

Michiel Salters


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: smeyers@aristeia.com (Scott Meyers)
Date: 1999/09/09
Raw View
On 08 Sep 99 19:17:00 GMT, Valentin Bonnard wrote:
> Marco Dalla Gasperina wrote:
>
> > Are you saying that the implementation is allowed to change the
> > value of the pointer deleted?
>
> yes
>
> Try to prove the contrary !

5.3.5/4 of the standard reads this way:

  The cast-expression in a delete-expression shall be evaluated  exactly
  once.   If the delete-expression calls the implementation deallocation
  function (_basic.stc.dynamic.deallocation_), and if the operand of the
  delete  expression  is not the null pointer constant, the deallocation
  function will deallocate the storage referenced by  the  pointer  thus
  rendering  the  pointer  invalid.   [Note: the value of a pointer that
  refers to deallocated storage is indeterminate.  ]

It seems pretty clear to me that the last sentence allows the value of a
pointer to be changed as a side-effect of deleting the pointer.  Presumably
this includes the "this" pointer.  Under the assumption that nothing in the
object is referenced after deleting "this", however, I see no reason why
the above paragraph would invalidate the practice of deleting "this".  In
fact, I happen to think it's reasonable practice under restricted
circumstances, including those under which I use it in Item 29 of More
Effective C++.  I'd be interested in arguments to the contrary.

FWIW, my sense is that the members of the C++ standardization committees
didn't mean to outlaw "delete this", but that's a guess on my part; I've
never been on any of the committees.

Scott

--
Scott Meyers, Ph.D.                  smeyers@aristeia.com
Software Development Consultant      http://www.aristeia.com/
Visit http://meyerscd.awl.com/ to demo the Effective C++ CD


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1999/09/09
Raw View
In article <MPG.1240e515d4f641d49896cc@news.teleport.com>,
Scott Meyers <smeyers@aristeia.com> wrote:

>FWIW, my sense is that the members of the C++ standardization committees
>didn't mean to outlaw "delete this"

They didn't.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1999/09/09
Raw View
In article <37D79ACD.8AA70E66@lucent.com>, Salters  <salters@lucent.com> wrote:

>Valentin Bonnard wrote:

>> Marco Dalla Gasperina wrote:

>> > Are you saying that the implementation is allowed to change the
>> > value of the pointer deleted?

>> yes

>> Try to prove the contrary !

>> If you can't them I can say that it does change the value.

>Well, in that case it must be forbidden to delete a const pointer.

No, that doesn't follow.

The point is that after you execute `delete p;'  p has become an
invalid pointer.  There are very strong restrictions on what you
can do with such pointers -- in particular, you are not permitted
even to copy the value of such a pointer, whether or not you attempt
to examine the memory to which it points.  As a result, it is
difficult even to write a well-defined program that detects
whether or not the value of p has changed.  For example, you
cannot write

 q = p;
 delete p;
 if (p == q) { /* ... */ }

because the result of the comparison p == q is undefined, so an
implementation is permitted to do absolutely anything, including
terminating the entire program.
--
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              ]