delete a pointer

J

James Kanze

What bugs will hide:
delete a;
a = NULL;
From what it will hide these? Sounds surprizing. It exposes
bugs and does not hide. You should explain how this rule is
harmful.

It creates the impression that it exposes bugs, but it doesn't.
(I don't think it hides any, however. It just gives a false
sense of security.)

The one case such a rule might make sense is if you're using
garbage collection, since a garbage collector won't collect the
memory if there is a valid pointer to it (even if the destructor
has run). Most of the time, even there, however, there's no
point in it, since the pointer will either be reused, or go out
of scope.

The only time this rule makes any sense at all is if the pointer
will be reused, but not immediately, and you have to check to
determine whether it is already in use before reusing it. (The
classical example is a cached computed value. If you do
anything which might change the value, you delete and null the
pointer, and if you need the value, you check for null before
recalculating it.)
 
J

James Kanze

It also doesn't want to add language rules that mislead people
into thinking they've done something safe.

Or that can't be implemented except in specific cases. The
language doesn't require the argument to delete to be an lvalue,
so there's no way that it can require it to be set to null (or
any other value).

(For the rest, of course, you're right that even when the
compiler could do it, it's worthless.)
 
J

James Kanze

Here is one example where setting to null would have some use
although I would say this is a bad practice and not very clean
code - it can be probably restructured to be much cleaner:
int *a = new Object();
a->DoStuff();
if (some event) { delete a; a = null; }
// do something else
if (a != null)
{
// code if object is still defined
a->DoMoreStuff();
}
else
{
// code if object is undefined, print error or whatever
}

This is actually a more or less standard pattern, except that in
the else branch, you would construct a new object, i.e.:

// In separate functions...
if (something happened which would change the value of a) {
delete a;
a = NULL;
}

// In function which needs the value of a:
if ( a == NULL )
a = new Object;

(Of course, you initialize a with NULL.)
 
B

Balog Pal

Back9 said:
delete a; <== my code

//His comments : You must set the ptr values back to NULL after
delete.

I know that it is good practice after deleting a pointer variable, to
set it NULL.
But my question is is it reuqired?
I hope somebody shows me c++ delete rules on this.

Rather tell us why you did not set the pointer to NULL, and what benefit a
variable holding a n invalid pointer (that invokes undefined behavior even
by inspecting) has?

Normally the cases where you skip NULL-setting are where the variable is
immediately assigned some other pointer value or disappears leaving scope.
 
B

Balog Pal

James Kanze said:
It's certainly not a C++ rule, and it's not generally considered
good practice (except in specific cases), since it doesn't buy
you anything.

You mean except for the wine, the sanitation, the roads,, and the
program-wide invariant of "all pointers are either valid or NULL"?
 
K

Kai-Uwe Bux

Balog said:
You mean except for the wine, the sanitation, the roads,, and the
program-wide invariant of "all pointers are either valid or NULL"?

The practice of setting a pointer variable to NULL after deletion does not,
in itself, ensure the program-wide invariant "all pointers are either valid
or NULL". When this invariant is desired, it requires much more careful
design and a global perspective on all pointer variables. Pure local coding
rules do not suffice. (Alternatively, one can use a special smart-pointer
that ensures that _all_ pointer variables pointing to the same object are
NULLed when one of them is deleted.)


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

* Kai-Uwe Bux:
* Balog Pal:

The practice of setting a pointer variable to NULL after deletion does not,
in itself, ensure the program-wide invariant "all pointers are either valid
or NULL". When this invariant is desired, it requires much more careful
design and a global perspective on all pointer variables. Pure local coding
rules do not suffice. (Alternatively, one can use a special smart-pointer
that ensures that _all_ pointer variables pointing to the same object are
NULLed when one of them is deleted.)

Just a terminology note: "valid" is not defined for pointers in the standard,
but is used. And one can infer the meaning "not causing UB upon rvalue
conversion", e.g. when assigning pointer values. With this meaning a nullpointer
is a valid pointer, as is e.g. a+n for a raw array a of n items.

I.e., with the standard's apparent terminology one would talk about the
program-wide invariant "all pointers are valid".

I think the term RealGood would be proper for a dereferencable pointer where the
pointee can be used, if one finds "dereferencable pointer where the pointee can
be used" to be too much of a mouthful (and I do). However I don't expect anyone
to use this term. After all, nobody does.

And I think the intention above was /not/ to say "all pointers are valid",
because having e.g. a+n around can be pretty dangerous even though it's valid.

I think the intention was to say "any stored pointer is RealGood or 0".


Cheers,

- Alf (nit-picking, but those are important distinctions)
 
K

Kai-Uwe Bux

Alf said:
* Kai-Uwe Bux:

Just a terminology note: "valid" is not defined for pointers in the
standard, but is used.
[...]

In [3.9.2/3] the standard uses/introduces the term "valid value of an object
of pointer type":

...
A valid value of an object pointer type represents either the address of a
byte in memory (1.7) or a null pointer (4.10). If an object of type T is
located at an address A, a pointer of type cv T* whose value is the
address A is said to point to that object, regardless of how the value was
obtained.
...

The statement could be mistaken for a definition, but the term "valid" is
not in italics. So, you are correct that the standard does not define the
term. What the next sentence suggests, is that "pointing to an object" is
defined (especially since "point" is in italics).
I.e., with the standard's apparent terminology one would talk about the
program-wide invariant "all pointers are valid".
[...]

All pointer type object values are 0 or pointing. <g>


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

Alf said:
* Kai-Uwe Bux:

Just a terminology note: "valid" is not defined for pointers in the
standard, but is used.
[...]

In [3.9.2/3] the standard

You mean the C++0x draft.

uses/introduces the term "valid value of an object
of pointer type":

...
A valid value of an object pointer type represents either the address of a
byte in memory (1.7) or a null pointer (4.10). If an object of type T is
located at an address A, a pointer of type cv T* whose value is the
address A is said to point to that object, regardless of how the value was
obtained.
...

The statement could be mistaken for a definition, but the term "valid" is
not in italics. So, you are correct that the standard does not define the
term. What the next sentence suggests, is that "pointing to an object" is
defined (especially since "point" is in italics).

I wasn't aware that what looks like a definition had been added in the C++0x
draft, that would be very nice! :)

On the other hand, if this is regarded as a definition then it would define a
dangling pointer as valid :-(.

So I think, like you, that it's not a definition but rather just a requirement
(among more) on valid pointers. Perhaps that should ideally be clarified in the
text. It's difficult to formally define "valid pointer" in C++...

I.e., with the standard's apparent terminology one would talk about the
program-wide invariant "all pointers are valid".
[...]

All pointer type object values are 0 or pointing.<g>

Well, almost. You can do things such as reinterpret_cast<int*>( 123456 ) and
have something that is a pointer value but doesn't necessarily "point", since
there's not necessarily any such byte in memory, and isn't valid.


Cheers,

- Alf
 
K

Kai-Uwe Bux

Alf said:
Alf said:
* Kai-Uwe Bux:
* Balog Pal:
* James Kanze:
*<unspecified author>

I know that it is good practice after deleting a pointer variable,
to set it NULL.
But my question is is it reuqired?
I hope somebody shows me c++ delete rules on this.

It's certainly not a C++ rule, and it's not generally considered
good practice (except in specific cases), since it doesn't buy
you anything.

You mean except for the wine, the sanitation, the roads,, and the
program-wide invariant of "all pointers are either valid or NULL"?

The practice of setting a pointer variable to NULL after deletion does
not, in itself, ensure the program-wide invariant "all pointers are
either valid or NULL". When this invariant is desired, it requires much
more careful design and a global perspective on all pointer variables.
Pure local coding rules do not suffice. (Alternatively, one can use a
special smart-pointer that ensures that _all_ pointer variables
pointing to the same object are NULLed when one of them is deleted.)

Just a terminology note: "valid" is not defined for pointers in the
standard, but is used.
[...]

In [3.9.2/3] the standard

You mean the C++0x draft.

No, I mean: ISO/IEC 14882:2003(E). At least, that is in the upper right hand
corner of the page from where I copied.

uses/introduces the term "valid value of an object
of pointer type":

...
A valid value of an object pointer type represents either the address
of a byte in memory (1.7) or a null pointer (4.10). If an object of
type T is located at an address A, a pointer of type cv T* whose value
is the address A is said to point to that object, regardless of how
the value was obtained.
...

The statement could be mistaken for a definition, but the term "valid" is
not in italics. So, you are correct that the standard does not define the
term. What the next sentence suggests, is that "pointing to an object" is
defined (especially since "point" is in italics).

I wasn't aware that what looks like a definition had been added in the
C++0x draft, that would be very nice! :)

On the other hand, if this is regarded as a definition then it would
define a dangling pointer as valid :-(.

So I think, like you, that it's not a definition but rather just a
requirement (among more) on valid pointers. Perhaps that should ideally be
clarified in the text. It's difficult to formally define "valid pointer"
in C++...

I.e., with the standard's apparent terminology one would talk about the
program-wide invariant "all pointers are valid".
[...]

All pointer type object values are 0 or pointing.<g>

Well, almost. You can do things such as reinterpret_cast<int*>( 123456 )
and have something that is a pointer value but doesn't necessarily
"point", since there's not necessarily any such byte in memory, and isn't
valid.

I am not sure, that reinterpret_cast<int*>( 123456 ) qualifies as an
expression that yields the value of a "pointer type object" unless there
happens to reside an int* at address 123456. Have to think about it.


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Kai-Uwe Bux said:
Alf said:
Alf P. Steinbach wrote:

* Kai-Uwe Bux: [...
All pointer type object values are 0 or pointing.<g>

Well, almost. You can do things such as reinterpret_cast<int*>( 123456 )
and have something that is a pointer value but doesn't necessarily
"point", since there's not necessarily any such byte in memory, and isn't
valid.

I am not sure, that reinterpret_cast<int*>( 123456 ) qualifies as an
expression that yields the value of a "pointer type object" unless there
happens to reside an int* at address 123456. Have to think about it.

Nevermind the "unless ...". What I have to think about is this difference: a
program can manipulate objects, some of them, say int objects. Now, these
int objects have values. And 5 does not need to be one of them although the
expression 5 yields an int value that can be used in the program.
Nonetheless it would not be the value of one of the int objects manipulated
by the program. Similarly, reinterpret_cast<int*>( 123456 ) can yield an
int* value that is not the value of any int* object manipulated by the
program.


Best

Kai-Uwe Bux
 
J

James Kanze

You mean except for the wine, the sanitation, the roads,, and
the program-wide invariant of "all pointers are either valid
or NULL"?

It doesn't buy you that last invariant, and the strongest
argument against using it is that it creates a false sense of
security. The proof being that someone of your experience and
knowledge seems to be mislead by it. (That last sentence is
*not* meant to be ironic. I've seen enough of Balog's postings
to know that he really does know C++.)

The only way to ensure that that last invariant holds is to use
garbage collection and ban the unary & operator. (In fact, if
you really mean it, you'd have to also ban destructors and all
functions with destructor like semantics: dispose, etc. Which
is why even languages like Java, which use garbage collection
and don't allow local objects, can't really enforce this
invariant.)
 
J

James Kanze

* Kai-Uwe Bux:

[...]
Just a terminology note: "valid" is not defined for pointers
in the standard, but is used. And one can infer the meaning
"not causing UB upon rvalue conversion", e.g. when assigning
pointer values. With this meaning a nullpointer is a valid
pointer, as is e.g. a+n for a raw array a of n items.

I'm not sure it has to be defined. All that's required is that
the standard be clear as to when a pointer is "valid", and what
you can or cannot do with a pointer that is or is not "valid".

Not that I'm convinced that the standard even achieves this.
Off hand, if I were reformulating this, I'd say that there are
four categories of pointers: pointers to valid objects, pointers
to one past the end of an array, null pointers and invalid
pointers. And then reformulate much of the rules concerning
pointers in terms of these categories. For the issue in
question: I'm pretty sure that the intent of the standard is
that an lvalue to rvalue convertion of an invalid pointer
(according to my definition immediately above) results in
undefined behavior. But my certitude is based at least
partially on discussions I've had with some of the original
authors of the C90 standard. (And I rather think that the
motivation for this undefined behavior is irrelevant today, if
it ever was relevant.)
 
J

James Kanze

On 09.05.2010 02:16, * Kai-Uwe Bux:

[...]
Well, almost. You can do things such as
reinterpret_cast<int*>( 123456 ) and have something that is a
pointer value but doesn't necessarily "point", since there's
not necessarily any such byte in memory, and isn't valid.

You can get such pointer "values" in other ways, as well. An
uninitialized pointer, for example. Or if what was pointed to
was deleted, and the implementation unmaps memory on delete (so
the pointer no longer points to mapped memory).
 
Ö

Öö Tiib

It creates the impression that it exposes bugs, but it doesn't.
(I don't think it hides any, however.  It just gives a false
sense of security.)

It does give that "this pointer does not propagate dangling values"
sense of security. How this is false sense?
The one case such a rule might make sense is if you're using
garbage collection, since a garbage collector won't collect the
memory if there is a valid pointer to it (even if the destructor
has run).  Most of the time, even there, however, there's no
point in it, since the pointer will either be reused, or go out
of scope.

Assigning 0 to pointer is valid form of reusing it. 0 is useful value
of pointer. Value that points at unavailable places causes bugs when
it is used.
The only time this rule makes any sense at all is if the pointer
will be reused, but not immediately, and you have to check to
determine whether it is already in use before reusing it.  (The
classical example is a cached computed value.  If you do
anything which might change the value, you delete and null the
pointer, and if you need the value, you check for null before
recalculating it.)


It seems like there are just fixed set of cases. In some cases
assigning 0 is pointless and in other cases it is fruitful. The cases
when the rule does not make sense are when pointer is immediately
reused again or leaves scope or is destroyed itself.
 
A

Alf P. Steinbach

It does give that "this pointer does not propagate dangling values"
sense of security. How this is false sense?

First, you can have more than one pointer to the same object, and in that case
the assignment of 0 just lies.

Secondly, the only purpose of the 0 is to check it. Checking it means that the
code holds on to that pointer variable so that there's a need for checking it.
This in turn means fewer invariants available and higher complexity, which means
higher probability of bugs, not lower.

And so it *can* give a false sense of security.

On the other hand, 0 can be more likely to be detected when the pointer is later
used incorrectly.

So it all depends.

Assigning 0 to pointer is valid form of reusing it. 0 is useful value
of pointer. Value that points at unavailable places causes bugs when
it is used.

No, such values do not cause bugs. They /are/ bugs. But I think you mean that
it's easier to detect incorrect use of a pointer when it's 0, and it may be.

It seems like there are just fixed set of cases. In some cases
assigning 0 is pointless and in other cases it is fruitful. The cases
when the rule does not make sense are when pointer is immediately
reused again or leaves scope or is destroyed itself.

Or when there are other pointers to the object. Or when the quality is high
enough that the costs of assigning 0 outweights the marginal advantage. The
costs include false sense of security, more code, and being steered towards
using unsafe raw pointer handling.

So, again, it all depends.


Cheers, & hth.,

- Alf
(blog at <url: alfps.wordpress.com>, started on thursday)
 
K

Kai-Uwe Bux

Alf said:
On 09.05.2010 14:38, * Öö Tiib: [...]
Assigning 0 to pointer is valid form of reusing it. 0 is useful value
of pointer. Value that points at unavailable places causes bugs when
it is used.

No, such values do not cause bugs. They /are/ bugs.
[...]

The statement seems to strong. E.g., if you have an array, you could use

T * result = std::find( a, a+length, some_value );

and if the value is not found, result will point past the array. That is not
a bug but the standard way for find to flag that the value wasn't found.


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

Alf said:
On 09.05.2010 14:38, * Öö Tiib: [...]
Assigning 0 to pointer is valid form of reusing it. 0 is useful value
of pointer. Value that points at unavailable places causes bugs when
it is used.

No, such values do not cause bugs. They /are/ bugs.
[...]

The statement seems to strong. E.g., if you have an array, you could use

T * result = std::find( a, a+length, some_value );

and if the value is not found, result will point past the array. That is not
a bug but the standard way for find to flag that the value wasn't found.

I think the context here was having a dangling pointer versus assigning 0.

But technically (literally) you have a point. :)


Cheers,

- Alf
(shameless plug for my blog: <url: http://alfps.wordpress.com/>, just started)
 
Ö

Öö Tiib

First, you can have more than one pointer to the same object, and in that case
the assignment of 0 just lies.

Sure. Then i attempt to set the other pointers to that object also to
0. NULL value shows that these pointers point at nothing now.
Secondly, the only purpose of the 0 is to check it. Checking it means that the
code holds on to that pointer variable so that there's a need for checking it.
This in turn means fewer invariants available and higher complexity, which means
higher probability of bugs, not lower.

Yes. There are no ways to check if pointer has valid value. Or are
there?
And so it *can* give a false sense of security.

On the other hand, 0 can be more likely to be detected when the pointer is later
used incorrectly.

So it all depends.



No, such values do not cause bugs. They /are/ bugs. But I think you mean that
it's easier to detect incorrect use of a pointer when it's 0, and it may be.

Yes, i did mean that it is bug when detecting for 0 does not help
anymore. There should be the information somewhere that the pointer is
pointing at nothing. Pointer itself is most natural place for that
information i think.
Or when there are other pointers to the object. Or when the quality is high
enough that the costs of assigning 0 outweights the marginal advantage. The
costs include false sense of security, more code, and being steered towards
using unsafe raw pointer handling.

So, again, it all depends.

What is the safer raw pointer handling? I see what you mean by false
sense of security. People think that setting pointer to NULL helps
with more things than it helps.
 
B

Balog Pal

Kai-Uwe Bux said:
The practice of setting a pointer variable to NULL after deletion does
not,
in itself, ensure the program-wide invariant "all pointers are either
valid
or NULL".

Of course in itself it doesn't. However leaving the pointer variable hanging
around after deletion ensures that you can't have it.
When this invariant is desired, it requires much more careful
design and a global perspective on all pointer variables.

Yeah, programming is hard. Correct programming even more so. We need
methods, attention, and a deal of luck too.

That observation is no grounds to do fishy things without even an attempt to
explanation why...
Pure local coding rules do not suffice.

And lack of them suffice even less. Or ignoring them on a just a whim.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top