Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Checking whether a pointer has been deleted

455 views
Skip to first unread message

Zedzed

unread,
Jun 6, 2006, 9:36:54 AM6/6/06
to
Hi

Having discovered that the following is undefined:

MyClass* p = new myClass();
delete p;

if (p) //behaviour is not defined


How does one test whether a pointer has been deleted or not. I always
thought that that was the benefit of references over pointers - one
always had to check with pointers but with references there is never a
need to. Or am I missing something here?

tx


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Thomas Maeder

unread,
Jun 6, 2006, 6:02:59 PM6/6/06
to

"Zedzed" <pete.c...@gmail.com> writes:

> Having discovered that the following is undefined:
>
> MyClass* p = new myClass();

MyClass or myClass?


> delete p;
>
> if (p) //behaviour is not defined
>
>
> How does one test whether a pointer has been deleted or not.

std::auto_ptr<MyClass> p(new MyClass);
p.reset();

if (p.get()==NULL)
; // object previously owned by p was deleted or passed on
else
; // none of the above


> I always thought that that was the benefit of references over
> pointers - one always had to check with pointers but with references
> there is never a need to. Or am I missing something here?

Reference types don't have null values, and references can't be
reassigned. Therefore it's a good idea to use a reference if these
restrictions are what you need, and a (dump or smart) pointer
otherwise.

That said, another condition for using a reference is when the syntax
requires it (as in overloaded operators).

Edson Manoel

unread,
Jun 6, 2006, 6:05:52 PM6/6/06
to
> How does one test whether a pointer has been deleted or not.

You can always zero your pointers after a delete, e.g:

MyClass* p = new myClass();
delete p;

p = 0;
if (p) // ...

> one always had to check with pointers but with references there is never a
> need to. Or am I missing something here?

It depends. You can have invalid references too, e.g:

MyClass* p = new myClass();
delete p;

CallByRef(*p);

//...

void CallByRef(MyClass &p) {
p->something; // invalid access
}

You can use smart pointers too, see
http://www.boost.org/libs/smart_ptr/smart_ptr.htm, they are better
checked and better behaved after a 'deletion'.

v04...@gmail.com

unread,
Jun 6, 2006, 6:01:24 PM6/6/06
to
> MyClass* p = new myClass();
> delete p;
>
> if (p) //behaviour is not defined

AFAIK behaviour is well defined.
18.4.1.1.3 says that new must return non-null pointer.
"delete p" don't affects to p, so p points to old non-null address.

check "if (p)" will always success.

probably after "delete p;" you have to write "p = 0;"

Krishanu Debnath

unread,
Jun 7, 2006, 4:56:13 PM6/7/06
to
v04...@gmail.com wrote:
>> MyClass* p = new myClass();
>> delete p;
>>
>> if (p) //behaviour is not defined
>
> AFAIK behaviour is well defined.
> 18.4.1.1.3 says that new must return non-null pointer.
> "delete p" don't affects to p, so p points to old non-null address.
>
> check "if (p)" will always success.

Now read 5.3.5p4

Krishanu

Gerhard Menzl

unread,
Jun 7, 2006, 5:04:53 PM6/7/06
to
Edson Manoel wrote:

> It depends. You can have invalid references too, e.g:

Not really.

> MyClass* p = new myClass();
> delete p;
> CallByRef(*p);

You invoke undefined behaviour the moment you dereference the pointer,
before the reference is created.

> //...
>
> void CallByRef(MyClass &p) {
> p->something; // invalid access
> }

This should not compile (unless MyClass defines operator->). Assuming
that you meant to write

p.something;

you cannot rely on even getting that far because your troubles start
before the function is called.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

The information contained in this e-mail message is privileged and
confidential and is for the exclusive use of the addressee. The person
who receives this message and who is not the addressee, one of his
employees or an agent entitled to hand it over to the addressee, is
informed that he may not use, disclose or reproduce the contents thereof.

kanze

unread,
Jun 7, 2006, 4:59:31 PM6/7/06
to
Edson Manoel wrote:
> > How does one test whether a pointer has been deleted or not.

> You can always zero your pointers after a delete, e.g:

> MyClass* p = new myClass();
> delete p;
> p = 0;
> if (p) // ...

That doesn't help much unless you can be 100% sure of finding
all of the pointers to the object.

An even better solution, when possible, is to arrange for the
pointer to go out of scope immediately after the delete.

> > one always had to check with pointers but with references
> > there is never a need to. Or am I missing something here?

> It depends. You can have invalid references too, e.g:

> MyClass* p = new myClass();
> delete p;
> CallByRef(*p);

> //...
>
> void CallByRef(MyClass &p) {
> p->something; // invalid access
> }

Here, the error is present in the call itself, not in the called
function. But that doesn't really change your point; invalid
references are definitly possible.

> You can use smart pointers too, see
> http://www.boost.org/libs/smart_ptr/smart_ptr.htm, they are
> better checked and better behaved after a 'deletion'.

The boost pointers normally take care of the deletion
themselves. The standard auto_ptr is probably more like what
you are looking for: assign NULL to it, and the object will be
deleted. It also ensures that there is only that one pointer to
the object, so you don't have to worry about other pointers
dangling.

Of course, it also ensures that there is only that one pointer
to the object, so if you need other pointers to the object, you
need a different solution.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kanze

unread,
Jun 7, 2006, 5:00:44 PM6/7/06
to
v04...@gmail.com wrote:
> > MyClass* p = new myClass();
> > delete p;

> > if (p) //behaviour is not defined

> AFAIK behaviour is well defined.
> 18.4.1.1.3 says that new must return non-null pointer.
> "delete p" don't affects to p, so p points to old non-null address.

The standard (§5.3.5/4) clearly says that after a delete
expression, the pointer value is invalid. Accessing an invalid
value is undefined behavior.

§18.4.1.1.3 doesn't say anything about the delete operator; it
defines the required semantics for the operator delete function,
which is only part of what the delete operator does. I don't
think it's completely clear whether the delete operator can
modify the bit pattern of a pointer, when its operand is an
lvalue, but it doesn't matter. Whether the bit pattern is
modified or not, the pointer is invalid.

> check "if (p)" will always success.

> probably after "delete p;" you have to write "p = 0;"

That doesn't really change anything. You can test if a pointer
is null, and in some cases, writing "p = NULL ;" makes sense,
but it only affects that one particular pointer, not other
pointers to the same element, and in the general case, is of no
use whatsoever.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kwijibo28

unread,
Jun 7, 2006, 6:18:50 PM6/7/06
to

Edson Manoel wrote:
> MyClass* p = new myClass();
> delete p;
> CallByRef(*p);
>
> //...
>
> void CallByRef(MyClass &p) {
> p->something; // invalid access
> }
>

I just want to correct a typo.
Member variable are access with the '.' operator when using references.
So we should read:

void CallByRef(MyClass &p) {
p.something; // invalid access
}

Regards,
Kwijibo28

werasm

unread,
Jun 7, 2006, 6:21:43 PM6/7/06
to

v04...@gmail.com wrote:
> > MyClass* p = new myClass();
> > delete p;
> >
> > if (p) //behaviour is not defined
>
> AFAIK behaviour is well defined.
> 18.4.1.1.3 says that new must return non-null pointer.
> "delete p" don't affects to p, so p points to old non-null address.
>
> check "if (p)" will always success.
>
> probably after "delete p;" you have to write "p = 0;"

See c++std98 3.7.3.2/4.

In short, this states that...
if(p)
...is undefined behaviour, as this uses the invalid ptr value. You can
however assign to p:

p = NULL; //is ok

as this does not use the invalidated pointer value.

Regards,

W

Vladimir Marko

unread,
Jun 7, 2006, 6:20:53 PM6/7/06
to
v04...@gmail.com wrote:
> > MyClass* p = new myClass();
> > delete p;
> >
> > if (p) //behaviour is not defined
>
> AFAIK behaviour is well defined.
> 18.4.1.1.3 says that new must return non-null pointer.
> "delete p" don't affects to p, so p points to old non-null address.
>
> check "if (p)" will always success.
> [...]

As the OP wrote accessing the value of the pointer after deleting the
pointed-to object results in undefined behaviour. There's been many
threads about this in clc++m and a classic example is a 80386
compatible processor. The 80386 memory access model is quite
complicated and there are many ways to implement a "pointer".
One involves a pair (selector,offset) and loading a wrong selector
in any of the selector registers is an error (General Protection Fault
if I remember correctly). Deleting an object could result in freeing
the entry in a selector translation table and subsequent load of the
pointer value could fail.

Cheers

Vladimir Marko

Bo Persson

unread,
Jun 8, 2006, 6:31:44 AM6/8/06
to

"Zedzed" <pete.c...@gmail.com> skrev i meddelandet
news:1149578839....@u72g2000cwu.googlegroups.com...

> Hi
>
> Having discovered that the following is undefined:
>
> MyClass* p = new myClass();
> delete p;
>
> if (p) //behaviour is not defined
>
>
> How does one test whether a pointer has been deleted or not.

You don't - you have to know that from the program flow.

One common way is to let the pointer go out of scope after the
pointed-to object is deleted.

void f()
{


MyClass* p = new myClass();

// lots of operations

delete p;

}

The pointer p isn't visible outside of the functions, so there is no
problem.

> I always
> thought that that was the benefit of references over pointers - one
> always had to check with pointers but with references there is never
> a
> need to. Or am I missing something here?

One advantage of references is that they cannot be null. For pointers
you might have to check that.


The easies way to avoid pointer troubles is not to use them!

If you put your class objects in a std::vector (or some other suitable
container), the container will manage the objects for you. Much
easier!


Bo Persson

john...@yahoo.com

unread,
Jun 8, 2006, 6:44:59 AM6/8/06
to
Zedzed wrote:

> Having discovered that the following is undefined:
>
> MyClass* p = new myClass();
> delete p;
>
> if (p) //behaviour is not defined
>
>
> How does one test whether a pointer has been deleted or not.

It sounds like you're confusing two issues: (a) whether the pointer is
null and (b) whether the object pointed to has been deleted. These are
unrelated (except that a null pointer obviously can't point to a
deleted object.)

The test if(p) will tell you whether the pointer is null or non-null.
It won't tell you whether the object pointed to by a non-null pointer
is still "alive."

Similarly with references, a reference cannot be null (well, it
can...but the code that initializes a "null reference" has undefined
behavior), but it can be "dangling," meaning it refers to an object
after the object's lifetime has ended.

john...@yahoo.com

unread,
Jun 8, 2006, 6:43:48 AM6/8/06
to
v04...@gmail.com wrote:
> > MyClass* p = new myClass();
> > delete p;
> >
> > if (p) //behaviour is not defined
>
> AFAIK behaviour is well defined.
> 18.4.1.1.3 says that new must return non-null pointer.
> "delete p" don't affects to p, so p points to old non-null address.
>

3.7.3.2/4 makes the behavior undefined. In particular, passing a
non-null pointer value to delete makes all pointers referring to the
deleted object "invalid," and the result of using an invalid pointer
value is undefined. "Using" is generally understood to mean anything
requiring lvalue-to-rvalue conversion (such as the if statement shown
above).

The reason this is undefined is that some architectures trap when you
load an invalid pointer into certain registers.

James Dennett

unread,
Jun 8, 2006, 6:48:58 AM6/8/06
to
v04...@gmail.com wrote:
>> MyClass* p = new myClass();
>> delete p;
>>
>> if (p) //behaviour is not defined
>
> AFAIK behaviour is well defined.

But it's not. (This has been discussed here and in comp.std.c++
a number of times.)

> 18.4.1.1.3 says that new must return non-null pointer.
> "delete p" don't affects to p, so p points to old non-null address.

After "delete p", the value of p is indeterminate; you
can't even check to see if it's changed (except by reading
it byte-by-byte, which gives fewer guarantees than you'd
want), and even if its bit pattern hasn't changed, the
implementation is allowed to mark that value as a trapping
value, so that any attempt to read it as a pointer will
terminate you program with a diagnostic (for example).

> check "if (p)" will always success.

Not portably. It's bug.

> probably after "delete p;" you have to write "p = 0;"

That's the only way you can be sure what if (p) will do
between calling delete p and setting p to point to other
allocated storage.

-- James

Jeffrey Schwab

unread,
Jun 8, 2006, 6:48:26 AM6/8/06
to
Zedzed wrote:

> How does one test whether a pointer has been deleted or not.

If you still might need to use the pointer after you've deleted it (i.e.
freed the object to which it pointed), zero it explicitly. E.g:

delete p;
p = 0;

If you find yourself having to check explicitly whether you've already
deleted a pointer, though, it may be time to refactor.

Seungbeom Kim

unread,
Jun 8, 2006, 6:53:06 PM6/8/06
to
Gerhard Menzl wrote:
> Edson Manoel wrote:
>
>> It depends. You can have invalid references too, e.g:
>
> Not really.
>
>> MyClass* p = new myClass();
>> delete p;
>> CallByRef(*p);
>
> You invoke undefined behaviour the moment you dereference the pointer,
> before the reference is created.

What about this?

MyClass* p = new MyClass();
MyClass& r = *p;
delete p;
// no UB up to this point
CallByRef(r);

Or this?

MyClass& r = *new MyClass();
delete &r;
// no UB up to this point
CallByRef(r);

My understanding is that a reference can also be invalid,
just as a pointer can.

--
Seungbeom Kim

Antti Virtanen

unread,
Jun 8, 2006, 6:50:51 PM6/8/06
to
On 2006-06-07, kanze <ka...@gabi-soft.fr> wrote:

>> probably after "delete p;" you have to write "p = 0;"
>
> That doesn't really change anything. You can test if a pointer
> is null, and in some cases, writing "p = NULL ;" makes sense,
> but it only affects that one particular pointer, not other
> pointers to the same element, and in the general case, is of no
> use whatsoever.

In my university, we recommend it to all students in programming
courses because accesses through the old pointer value might
do something, but accesses through null pointer are likely to trap
right at the moment of access.

t* p = new t();
delete p;
p->doSomething(); // UB, but might occasionally succeed
p = 0;
p->doSomething(); // will almost certainly abort the program right here

I'm not entirely sure if this zeroing is good style in the general case,
but the compiler can optimise it away in many cases. Personally I don't
like having to delete stuff manually anyway and prefer smart pointers or
automatic garbage collection.

--
// Antti Virtanen -//- http://www.students.tut.fi/~virtanea

kanze

unread,
Jun 8, 2006, 7:10:27 PM6/8/06
to
Gerhard Menzl wrote:
> Edson Manoel wrote:

> > It depends. You can have invalid references too, e.g:

> Not really.

Not really? Consider:

a.cc:
int a = 42 ;
extern int& f() ;
int& b = f() ;

int
g()
{
return b ;
}

int&
f()
{
return a ;
}

b.cc:

extern int g() ;

struct B
{
B() ;
int b ;
}

B objB ;

B::B()
: b( g() )
{
}

Now what is the state of the reference b in a.cc, when g() is
called from the constructor of the static objB, if the
initialization of b.cc occurs before the initialization of a.cc?

More simply, of course:

int&
f()
{
int a = 42 ;
return a ;
}

int
main()
{
int& r = f() ;
// What is the state of r?
}

Or:

int* p = new int( 42 ) ;
int& r = p ;
delete p ;
// What is the state of r?

It's actually pretty easy to get invalid references. With no
undefined behavior as long as you don't use them.

> > MyClass* p = new myClass();
> > delete p;
> > CallByRef(*p);

> You invoke undefined behaviour the moment you dereference the
> pointer, before the reference is created.

Agreed. Of course, since any behavior is possible, one possible
behavior is thus that you have an invalid reference:-).

But I agree that it's not really a valid example -- a good
compiler, when you compile in debugging mode, *will* abort the
program before creating the reference, and will abort the
program whether you use the reference or not. (A really good
compiler will give you an error message -- but it's far from
trivial to write a compiler that good.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Gerhard Menzl

unread,
Jun 9, 2006, 5:18:14 AM6/9/06
to
kanze wrote:

> Gerhard Menzl wrote:
>> Edson Manoel wrote:
>
>>> It depends. You can have invalid references too, e.g:
>
>> Not really.
>
> Not really? Consider:

[other examples snipped]

> int* p = new int( 42 ) ;
> int& r = p ;
> delete p ;
> // What is the state of r?
>
> It's actually pretty easy to get invalid references. With no
> undefined behavior as long as you don't use them.

Of course it is possible to get dangling references. My wording was too
sloppy; what I meant and should have written is that you cannot get
invalid references by dereferencing invalid pointers without invoking
undefined behaviour first.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

The information contained in this e-mail message is privileged and
confidential and is for the exclusive use of the addressee. The person
who receives this message and who is not the addressee, one of his
employees or an agent entitled to hand it over to the addressee, is
informed that he may not use, disclose or reproduce the contents thereof.

kanze

unread,
Jun 9, 2006, 6:13:40 PM6/9/06
to
Antti Virtanen wrote:
> On 2006-06-07, kanze <ka...@gabi-soft.fr> wrote:

> >> probably after "delete p;" you have to write "p = 0;"

> > That doesn't really change anything. You can test if a pointer is
> > null, and in some cases, writing "p = NULL ;" makes sense, but it
> > only affects that one particular pointer, not other pointers to the
> > same element, and in the general case, is of no use whatsoever.

> In my university, we recommend it to all students in programming
> courses because accesses through the old pointer value might do
> something, but accesses through null pointer are likely to trap right
> at the moment of access.

And what about accesses through other pointers which happened to point
to the same object. As a general rule, it's bad, because it gives a
false sense of security. There are, of course, special cases, but they
are just that.

> t* p = new t();
> delete p;
> p->doSomething(); // UB, but might occasionally succeed
> p = 0;
> p->doSomething(); // will almost certainly abort the program right here

But how often is that a problem? Compared with something like:

T* p = new T() ;
SomeObject o( p ) ; // Stores p, and uses it in the
destructor.
delete p ;

> I'm not entirely sure if this zeroing is good style in the general
> case, but the compiler can optimise it away in many cases. Personally
> I don't like having to delete stuff manually anyway and prefer smart
> pointers or automatic garbage collection.

Well, I'd say that garbage collection is the future. I use it in new
projects, when I can. (I've had problems using it with some third
party
libraries.) But even with manual management, I don't see where zeroing
the pointer buys you anything but a false sense of security, at least
in
the general case.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

0 new messages