By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,968 Members | 1,871 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,968 IT Pros & Developers. It's quick & easy.

Set a pointer to null when deleting?

P: n/a
When you delete a pointer, you should set it to NULL, right?

Joe
Apr 10 '06 #1
Share this Question
Share on Google+
51 Replies


P: n/a
Joe Van Dyk wrote:
When you delete a pointer, you should set it to NULL, right?


No. Your pointer should always be about to go out of scope, so don't bother
to NULL it.

If you must, use std::auto_ptr or boost::shared_ptr, and reset(NULL) that
(if I recall correctly).

Then their secret internal pointer will delete just before they go out of
scope, and they will take care of its NULL.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #2

P: n/a
Joe Van Dyk wrote:
When you delete a pointer, you should set it to NULL, right?


No. If you delete a pointer, it's probably a class member, and you're
deleting it from a destructor. In that case, you don't set it to 0,
because
noone will ever notice. The other common case is in assignments, but
in that case you will have new'ed a replacement object before. (You do
the new first, so if you run out of memory the assignment fails but the
old value is not lost).

Of course, if you use a smart pointer this is all automatic.

HTH,
Michiel Salters

Apr 10 '06 #3

P: n/a
Phlip wrote:
Joe Van Dyk wrote:
When you delete a pointer, you should set it to NULL, right?
No. Your pointer should always be about to go out of scope, so don't
bother to NULL it.


Nonsense. If my pointer is a data member and I am managing my own
memory, I should set it to null pointer in some cases. It doesn't
necessarily go out of scope right after deletion.
If you must, use std::auto_ptr or boost::shared_ptr, and reset(NULL)
that (if I recall correctly).
'boost' is non-standard. 'std::auto_ptr' is not suitable for some
cases due to its particular copy semantics.
[..]


V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 10 '06 #4

P: n/a
Mi*************@tomtom.com wrote:
Joe Van Dyk wrote:
When you delete a pointer, you should set it to NULL, right?
No. If you delete a pointer, it's probably a class member, and you're
deleting it from a destructor.


And if he's not?
In that case, you don't set it to 0,
because
noone will ever notice. The other common case is in assignments, [..]


What if the case *is* uncommon?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 10 '06 #5

P: n/a
On Mon, 10 Apr 2006 13:58:52 GMT, Joe Van Dyk <jo********@boeing.com>
wrote:
When you delete a pointer, you should set it to NULL, right?


You don't HAVE to.

But, while others here obviously disagree (I did read some of the
other replies), I say that you should get in the habit of always
setting pointer to NULL after you delete them, whether or not that has
any real effect (e.g. if it's about to go out of scope then NULL'ing
it has no effect but is still a good habit to get into).

It doesn't hurt and is often helpful.
Apr 10 '06 #6

P: n/a

C. J. Clegg wrote:
On Mon, 10 Apr 2006 13:58:52 GMT, Joe Van Dyk <jo********@boeing.com>
wrote:
When you delete a pointer, you should set it to NULL, right?


You don't HAVE to.
doesn't hurt and is often helpful.


And there it is. There is no reason NOT to beyond linespace fetishes.
It can save from hours to days debugging. In fact, if you set your
pointers to 0 all the time then some bugs will never bite you that
otherwise would have taken hours or days to debug. Deleting a 0
pointer is not an error, deleting any other pointer that has been
deleted already is and can be one of the most difficult types of errors
to track down.

It is one minor step you can use to help you keep bugs out of your
programs. Scope isn't the issue, getting in the habit of ALWAYS doing
it benefits you in numerous ways.

Apr 10 '06 #7

P: n/a
Joe Van Dyk wrote:
Victor Bazarov wrote:
Mi*************@tomtom.com wrote:
Joe Van Dyk wrote:

When you delete a pointer, you should set it to NULL, right?
No. If you delete a pointer, it's probably a class member, and you're
deleting it from a destructor.


And if he's not?

I'm not, actually.

Let's see if I can explain what's going on...

I've got an object (Object A) that contains two pointers to objects that
Object A didn't create.

There's another object in the system, Object B. Object B has a function
that requires an Object A pointer.

Object B gets deleted. It is (and out of my control) deleting the
Object A pointer. It's not setting the Object A pointer to NULL.

Now, there's threads involved here, so that may be complicating
things... but I was curious as to if the Object A pointer should be set
to NULL when Object B deletes it.

<snip>

Joe


Oh, and looking at the backtrace on the segfault, it's occuring right as
Object B deletes the pointer to Object A.

And right before I call that Object B function, I'm creating a new
Object A instance and sending a pointer to that object to Object B, if
that makes a difference.

I hope I explained that ok. I'm getting confused just thinking about
it. I'm not terribly smart, you see.

Apr 10 '06 #8

P: n/a
Victor Bazarov wrote:
Mi*************@tomtom.com wrote:
Joe Van Dyk wrote:
When you delete a pointer, you should set it to NULL, right?


No. If you delete a pointer, it's probably a class member, and you're
deleting it from a destructor.

And if he's not?


I'm not, actually.

Let's see if I can explain what's going on...

I've got an object (Object A) that contains two pointers to objects that
Object A didn't create.

There's another object in the system, Object B. Object B has a function
that requires an Object A pointer.

Object B gets deleted. It is (and out of my control) deleting the
Object A pointer. It's not setting the Object A pointer to NULL.

Now, there's threads involved here, so that may be complicating
things... but I was curious as to if the Object A pointer should be set
to NULL when Object B deletes it.

<snip>

Joe
Apr 10 '06 #9

P: n/a
Joe Van Dyk wrote:
[..]
Let's see if I can explain what's going on...

I've got an object (Object A) that contains two pointers to objects
that Object A didn't create.
So something like

class Other;
class A {
Other *not_mine_1, *not_mine_2;
public:
~A() {} // do nothing to pointers
};
There's another object in the system, Object B. Object B has a
function that requires an Object A pointer.
class B {
public:
void foo(A* aptr);
};
Object B gets deleted. It is (and out of my control) deleting the
Object A pointer.
Which A pointer? You didn't say that B _owned_ a dynamic A object.
It's not setting the Object A pointer to NULL.
Shouldn't be a problem _even_if_ the B actually owned that A and had
a pointer to that dynamic object.
Now, there's threads involved here, so that may be complicating
things... but I was curious as to if the Object A pointer should be
set to NULL when Object B deletes it.


Well, no. Your problem is most likely is elsewhere. Read about "The
Rule of Three" and follow it (concerning the B class). Also, make sure
you're not deleting that B object _twice_ somewhere.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 10 '06 #10

P: n/a

Joe Van Dyk wrote:
Object B gets deleted. It is (and out of my control) deleting the
Object A pointer. It's not setting the Object A pointer to NULL.


It probably can't. Unless the function taking the pointer requires a
pointer to pointer or a reference to a pointer then it can only set its
own copy of the pointer to 0. Pointers are just values that contain
number representing addresses in memory. If you pass a pointer by
value you can't exactly effect anything by setting that value to 0 on
the other side...the original copy of the pointer is unchanged.

So, whether or not Object B is setting the pointer to 0 is an unknown
at this time and it doesn't really matter. You need to keep in mind
that B is apparently taking ownership of the pointer it is passed and
act accordingly, by possibly copying the object and passing the copy or
some other solution that makes sense to your problem.

Apr 10 '06 #11

P: n/a
Joe Van Dyk wrote:
I'm¬*not¬*terribly¬*smart,¬*you¬*see.


Why aren't you using a smart pointer? Then they can do the thinking for you.
(Roughly..;)

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #12

P: n/a

"Joe Van Dyk" <jo********@boeing.com> wrote in message
news:Ix********@news.boeing.com...
When you delete a pointer, you should set it to NULL, right?

Joe


I'm a little surprised at the responses you've been getting from some very
experienced programmers. While a smart pointer might be the best solution
for your particular problem it doesn't answer your question.

I think the correct answer to your question should be: if you intend to
check the value of the pointer later on you should set it to NULL, otherwise
it doesn't matter. Some programs use the actual value of a pointer as a flag
whether it is pointing to something that needs to be deallocated. In those
cases you should null it when deleting. However, nothing in standard C++
depends on the value of a pointer after calling delete on it.

Also keep in mind that calling delete on a null value is a noop so you don't
need code like this:

if (ptr != 0)
delete ptr; // null-check not needed
Which allows you to write code like this (no endorsements made):

Foo *foo = 0;

:
:

if (allocFoo)
foo = new Foo;

:
:

if (deleteFoo)
{
delete foo;
foo = 0;
}

:
:

delete foo;
The code above is not that likely to occur as shown but inside
constructor/destructor code you might encounter this sequence of events.

Andrew


Apr 10 '06 #13

P: n/a
Victor Bazarov wrote:
Joe Van Dyk wrote:
[..]
Let's see if I can explain what's going on...

I've got an object (Object A) that contains two pointers to objects
that Object A didn't create.

So something like

class Other;
class A {
Other *not_mine_1, *not_mine_2;
public:
~A() {} // do nothing to pointers
};

There's another object in the system, Object B. Object B has a
function that requires an Object A pointer.

class B {
public:
void foo(A* aptr);

private:
A* aptr_; };

Object B gets deleted. It is (and out of my control) deleting the
Object A pointer.

Which A pointer? You didn't say that B _owned_ a dynamic A object.


void B::foo(A* aptr)
{
aptr_ = aptr;
}

B::~B()
{
delete aptr_;
}
It's not setting the Object A pointer to NULL.

Shouldn't be a problem _even_if_ the B actually owned that A and had
a pointer to that dynamic object.

Now, there's threads involved here, so that may be complicating
things... but I was curious as to if the Object A pointer should be
set to NULL when Object B deletes it.

Well, no. Your problem is most likely is elsewhere. Read about "The
Rule of Three" and follow it (concerning the B class). Also, make sure
you're not deleting that B object _twice_ somewhere.

V


Yes, it's entirely possible the problem is elsewhere. I was just
wondering if it was something silly I was doing.

Joe
Apr 10 '06 #14

P: n/a
Phlip wrote:
Joe Van Dyk wrote:

I'm not terribly smart, you see.

Why aren't you using a smart pointer? Then they can do the thinking for you.
(Roughly..;)


Because I need to pass a raw Object A pointer to Object's B function. I
(as of now) can't change the code of class B to use smart pointers. I
don't think a smart pointer can help me there...

Apr 10 '06 #15

P: n/a
andrew queisser wrote:
I'm a little surprised at the responses you've been getting from some very
experienced programmers.
Some of us know the textbook answer (set the friggin' pointer to NULL),
while some of us can't remember the last time we actually did that. There's
more reasons than smart pointers.

Another alternative is to set the pointer equal to the address of a static
NullObject. Consider this code:

p = getPointerFromWhatever();
if (p)
p->method(42);

Using NullObjects, that becomes this:

p = getPointerFromWhatever();
assert(p);
p->method(42);

The code is one tick simpler; it has one less 'if' statement.

Replacing conditional statements with the interactions of virtual methods is
what OO is all about.
I think the correct answer to your question should be: if you intend to
check the value of the pointer later on you should set it to NULL


Even if you don't intend to, if that pointer has remaining scope, set it to
NULL to make sure (on common implementations) you get a clean crash and not
memory corruption if you then accidentally try to dereference the pointer.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #16

P: n/a

Phlip wrote:
Another alternative is to set the pointer equal to the address of a static
NullObject. Consider this code:

p = getPointerFromWhatever();
if (p)
p->method(42);

Using NullObjects, that becomes this:

p = getPointerFromWhatever();
assert(p);
p->method(42);

The code is one tick simpler; it has one less 'if' statement.


Really? What is that assert doing there then?

What type does this static NullObject have?

Apr 10 '06 #17

P: n/a
Noah Roberts wrote:
p = getPointerFromWhatever();
assert(p);
p->method(42);

The code is one tick simpler; it has one less 'if' statement.
Really? What is that assert doing there then?


It is not increasing the mental burden of reading the function. And we could
migrate it inside a new function, getReferenceFromWhatever(), and this
function would be even shorter.
What type does this static NullObject have?


A type derived from Whatever class type that p points to, with
Whatever::method(int) overriden as a no-op.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #18

P: n/a

Phlip wrote:
Noah Roberts wrote:
p = getPointerFromWhatever();
assert(p);
p->method(42);

The code is one tick simpler; it has one less 'if' statement.
Really? What is that assert doing there then?


It is not increasing the mental burden of reading the function. And we could
migrate it inside a new function, getReferenceFromWhatever(), and this
function would be even shorter.


That statement just makes no sense. I can't parse it and it doesn't
seem to apply to the question at all.
What type does this static NullObject have?


A type derived from Whatever class type that p points to, with
Whatever::method(int) overriden as a no-op.


That requires three things:

1) a special "NullObject" class for each and every class that could
have a pointer to it.
2) a special "NullObject" static for each of the above implementations.
3) that all classes and all member functions are polymorphic!!

Consider also functions that return values...they cannot be noops!

Now #2 is only by consequence of your initial requirements...it isn't
actually required to be static but could simply be constructed. This
results in more small objects than a static though.

#3 is the real killer.

I don't think you have thought this through quite enough yet though.

Null *pointer* object is viable. Dereference would throw an exception
or pop an assert. This of course requires the use of some form of
smart pointer...which has already been suggested.

I don't see a good implementation brewing out of your NullObject
though.

Apr 10 '06 #19

P: n/a
Noah Roberts wrote:
>> p = getPointerFromWhatever();
>> assert(p);
>> p->method(42);
>>
>> The code is one tick simpler; it has one less 'if' statement.
>
> Really? What is that assert doing there then?
The function is less complex. It formerly had a visible controlled
statement.
> What type does this static NullObject have?
A type derived from Whatever class type that p points to, with
Whatever::method(int) overriden as a no-op.


That requires three things:

1) a special "NullObject" class for each and every class that could
have a pointer to it.
2) a special "NullObject" static for each of the above implementations.
3) that all classes and all member functions are polymorphic!!

Consider also functions that return values...they cannot be noops!


It also requires me to say, "Noah, I want you to find every pointer in your
program, and accomodate its pointee to have a potential NullObject _with_ a
no-op for every method."

Don't tempt me to. Instead, I will say this:

http://www.industriallogic.com/xp/re...ullObject.html

Now notice that is a _refactor_. It's not a Design Pattern, or even a
universally perfect goal. It's a path of improvement, away from redundant
'if' statements to check pointers.

The ideal situation has no 'if' statements, no pointers, and no need for
NullObjects.
Now #2 is only by consequence of your initial requirements...it isn't
actually required to be static but could simply be constructed. This
results in more small objects than a static though.
Yes, of course its storage class could be different than static. If the
pointer were smart, maybe another 'new' would work.

Because my NullObjects have no state, they can be static.
#3 is the real killer.
You made 3 up.
I don't think you have thought this through quite enough yet though.


Noope. I have indeed not thought thru all the things you will make up. ;-)

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #20

P: n/a

"Noah Roberts" <ro**********@gmail.com> wrote in message
news:11**********************@z34g2000cwc.googlegr oups.com...

[snip discussion about NullObject]
3) that all classes and all member functions are polymorphic!!


Not all, only the functions that need to be instrumented. Clearly
non-polymorphic functions cannot be rerouted to a NullObject but the rest of
the class is unaffected.
I think the discussion is really more about instrumentation strategies. The
OP indicated that he doesn't have control over all the code so it seems
futile to suggest reworking the class hierarchy.
Andrew
Apr 10 '06 #21

P: n/a

Phlip wrote:
Noah Roberts wrote:
3) that all classes and all member functions are polymorphic!! #3 is the real killer.


You made 3 up.


Really? Tell me then, what does the following code do?

class T
{
int * x;
public:
T() : x(0) {}
T(int v) : x(new int(x)) {}
void op() {*x = 0;}
};

class TNull : public T
{
public:
void op() {}
};

T * whatever() { return new TNull(); }

int main()
{
T * t = whatever();

t->op();

return 0;
}

If I just made #3 up then that code works, right? No undefined
behavior? Look again...you sure that your method of implementing null
object doesn't require polymorphic classes?

Look also at the problem implementing NullObject as a subclass of your
concrete object. What business does TNull have with an x? Does it
need it? Should it be there? Is TNull a T?

Simple piss poor setup yes, but it illustrates some of the problems.
What if op() did more than access a pointer? Since TNull is supposed
to represent an invalid T then how could anything performed by op() be
valid?

Refactoring works...at least in my experience. But you need to keep
certain details in mind. For instance that nullObject as shown in that
design *requires* polymorphic objects. Refactoring, like anything, can
be taken too far and you need to think about how the designs apply to
the language you are using to establish when, and when not, to use them.

Apr 10 '06 #22

P: n/a
>> I've got an object (Object A) that contains two pointers to objects that
Object A didn't create.

There's another object in the system, Object B. Object B has a function
that requires an Object A pointer.

Object B gets deleted. It is (and out of my control) deleting the Object
A pointer. It's not setting the Object A pointer to NULL.

Now, there's threads involved here, so that may be complicating things...
but I was curious as to if the Object A pointer should be set to NULL
when Object B deletes it.

<snip>

Joe


Oh, and looking at the backtrace on the segfault, it's occuring right as
Object B deletes the pointer to Object A.

And right before I call that Object B function, I'm creating a new Object
A instance and sending a pointer to that object to Object B, if that makes
a difference.

I hope I explained that ok. I'm getting confused just thinking about it.
I'm not terribly smart, you see.


Can your log the addresses of the A-objects in question after new-ing and
before deleting. Sounds like you're deleting something twice.

Andrew
Apr 10 '06 #23

P: n/a

andrew queisser wrote:
"Noah Roberts" <ro**********@gmail.com> wrote in message
news:11**********************@z34g2000cwc.googlegr oups.com...

[snip discussion about NullObject]
3) that all classes and all member functions are polymorphic!!


Not all, only the functions that need to be instrumented. Clearly
non-polymorphic functions cannot be rerouted to a NullObject but the rest of
the class is unaffected.


True, but you loose much of the benefit of a null object that way.
Clients would necessarily need to know which functions are ok to call
without checking and which are not. The class would need a function to
query whether it is valid or null so that clients can make the decision
before calling a function that is not polymorphic. This is a lot worse
than not having a null object in the first place because now you have a
mixture of methodologies....not good.
I think the discussion is really more about instrumentation strategies. The
OP indicated that he doesn't have control over all the code so it seems
futile to suggest reworking the class hierarchy.


Clearly.

Apr 10 '06 #24

P: n/a
Noah Roberts wrote:
> 3) that all classes and all member functions are polymorphic!!
Really? Tell me then, what does the following code do?


You didn't make "all member functions polymorphic".

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #25

P: n/a

Phlip wrote:
http://www.industriallogic.com/xp/re...ullObject.html

Now notice that is a _refactor_. It's not a Design Pattern, or even a
universally perfect goal. It's a path of improvement, away from redundant
'if' statements to check pointers.


I should also point out that NullObject *is* a design pattern;
"Introduce NullObject" is a refactor.

Apr 10 '06 #26

P: n/a
Noah Roberts wrote:

Phlip wrote:
http://www.industriallogic.com/xp/re...ullObject.html

Now notice that is a _refactor_. It's not a Design Pattern, or even a
universally perfect goal. It's a path of improvement, away from redundant
'if' statements to check pointers.
I should also point out that NullObject *is* a design pattern;
"Introduce NullObject" is a refactor.


NullObject is an object design. It may indeed be the target of a refactor,
and it might be cited in a book on "Refactoring to Patterns".

However, its design quality is not high enough to rank as a titular Design
Pattern, such as in a pattern book. (Before you go searching the dozens of
PLOP books for it, that would be an "argument by authority" that misses my
point.)

If you were to invent a complete object model from scratch, it should
minimize pointers, minimize 'if' checks on pointers, and not use
NullObject.
Clients would necessarily need to know which functions are ok to call
without checking and which are not.


Right - that is indeed one of its flaws. The GOF /Design Patterns/ don't
have that problem.

And if you indeed need a NullObject, that flaw is reduced if all your
classes are very small...

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #27

P: n/a

Phlip wrote:
Noah Roberts wrote:
> 3) that all classes and all member functions are polymorphic!!

Really? Tell me then, what does the following code do?


You didn't make "all member functions polymorphic".


Umm...yes, I know. That was the whole point of my illustration. You
said I made #3 up...I just showed why your design doesn't work unless
all members are polymorphic. Are you lost?

Apr 10 '06 #28

P: n/a
Noah Roberts wrote:
Umm...yes, I know. That was the whole point of my illustration. You
said I made #3 up...I just showed why your design doesn't work unless
all members are polymorphic. Are you lost?


Were you going to make operator= virtual?

Nobody said to make all members virtual, and your other posts have
repeatedly harped on that point. I have conceded, again and again, that
NullObject is not a "Good Thing" (while you seem to think it's as good as a
Design Pattern). So, no, I don't think I'm the one who is lost here. How
about you back off, take a deep breath, and learn some more about C++
alternatives to nulling pointers.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 10 '06 #29

P: n/a

Phlip wrote:
Noah Roberts wrote:

Phlip wrote:
http://www.industriallogic.com/xp/re...ullObject.html

Now notice that is a _refactor_. It's not a Design Pattern, or even a
universally perfect goal. It's a path of improvement, away from redundant
'if' statements to check pointers.
I should also point out that NullObject *is* a design pattern;
"Introduce NullObject" is a refactor.


NullObject is an object design. It may indeed be the target of a refactor,
and it might be cited in a book on "Refactoring to Patterns".

However, its design quality is not high enough to rank as a titular Design
Pattern, such as in a pattern book. (Before you go searching the dozens of
PLOP books for it, that would be an "argument by authority" that misses my
point.)


If you want to go that route you'll have to quantify how to call
something a pattern vs. not quite a pattern. The GOF book has several
very basic design patterns in it that are no more complex than the null
object. Just because it is not in GOF doesn't mean it is not a
pattern.

If you were to invent a complete object model from scratch, it should
minimize pointers, minimize 'if' checks on pointers, and not use
NullObject.
Clients would necessarily need to know which functions are ok to call
without checking and which are not.
Right - that is indeed one of its flaws. The GOF /Design Patterns/ don't
have that problem.


Ummm...some of the GOF patterns also require polymorphism as part of
the design and fail otherwise. In fact I would go as far as saying
most are that way.

And if you indeed need a NullObject, that flaw is reduced if all your
classes are very small...


You'll notice that in the link you provided the design does not specify
the complete object higherarchy. It is very likely that
MouseEventHandler is an abstract class having at least two concrete
classes - one being the null object. Small classes is not a
requirement of the design.

You are on your way but there seems to be several areas where you lack
a complete understanding. Same can be said of everyone of course.

Apr 10 '06 #30

P: n/a
Phlip wrote:
Noah Roberts wrote:
p = getPointerFromWhatever();
if (p)
p->method(42); p = getPointerFromWhatever();
assert(p);
p->method(42);

The code is one tick simpler; it has one less 'if' statement.


Really? What is that assert doing there then?


It is not increasing the mental burden of reading the function.


I find the if(p) version less burdensome to read, and simpler.
You mention that the assert version is "simpler" because it
does not have a "control structure". But the assert() is
performing control flow. What's worse is that that flow
is opaque: what happens when the assert fails? We can't
tell from this example. But in the if() code, if p is null
then we know exactly what will happen (the code will
continue on with whatever statements follow this snippet).

Apr 10 '06 #31

P: n/a

Old Wolf wrote:
I find the if(p) version less burdensome to read, and simpler.
You mention that the assert version is "simpler" because it
does not have a "control structure". But the assert() is
performing control flow. What's worse is that that flow
is opaque: what happens when the assert fails? We can't
tell from this example. But in the if() code, if p is null
then we know exactly what will happen (the code will
continue on with whatever statements follow this snippet).


I think for most cases the if (p) version is adiquate, simplest, and
more easily read/dealt with. There are some cases when a null object
is better such as when dealing with states where there can be a 'null'
state. If you have a bunch of polymorphic objects implementing an
abstract interface anyway it can be better to implement the null
condition with an actual object than with a 0 pointer...sometimes.
However, replacing every occurance of 'if(p)' with a null object is
crazyness and if you have no control over the class you are pointing to
it just plain won't work in most cases.

Apr 10 '06 #32

P: n/a
Old Wolf wrote:
Phlip wrote:
Noah Roberts wrote:

p = getPointerFromWhatever();
if (p)
p->method(42);

p = getPointerFromWhatever();
assert(p);
p->method(42);

The code is one tick simpler; it has one less 'if' statement.

Really? What is that assert doing there then?


It is not increasing the mental burden of reading the function.

I find the if(p) version less burdensome to read, and simpler.
You mention that the assert version is "simpler" because it
does not have a "control structure". But the assert() is
performing control flow. What's worse is that that flow
is opaque: what happens when the assert fails? We can't
tell from this example. But in the if() code, if p is null
then we know exactly what will happen (the code will
continue on with whatever statements follow this snippet).

Potentially dangerous without an else?

I'm not supporting the assert alternative, but there should be some
error handling. On a lot of systems, the assert would be largely
superfluous as attempting to dereference the (NULL) pointer would case a
crash.

--
Ian Collins.
Apr 10 '06 #33

P: n/a

Ian Collins wrote:
Potentially dangerous without an else?

I'm not supporting the assert alternative, but there should be some
error handling. On a lot of systems, the assert would be largely
superfluous as attempting to dereference the (NULL) pointer would case a
crash.


Well, in this case, the original code that used the assert used a 'null
object'. It was used as an argument for such constructs and the
question of how it applied was never really adiquately answered. The
idea was that with a normal pointer you had to use an if (p) p->do()
where with a null object you would assert(p); p->do();...and this is
simpler...

- shrug -

Apr 11 '06 #34

P: n/a

Noah Roberts skrev:
C. J. Clegg wrote:
On Mon, 10 Apr 2006 13:58:52 GMT, Joe Van Dyk <jo********@boeing.com>
wrote:
> When you delete a pointer, you should set it to NULL, right?
You don't HAVE to.
doesn't hurt and is often helpful.

It is not always helpful. Also the ptr = 0 sends the wrong message to
the reader - is the pointer reset now and then or what is it that takes
place. And there it is. There is no reason NOT to beyond linespace fetishes.
There is one very good reason: to verify your program logic. Accessing
a resource that is no longer present is an obvious programming error,
and setting the pointer to 0 might just prevent that situation from
being identified.
If you are going to set the pointer to anything, it is a far better
idea to set it to some illegal value the same way as operator delete
sets memory to an often illegal pattern in some debug builds.
If the pointer is used to designate an optional value, the situation is
different and you should set the pointer to 0. It can save from hours to days debugging. In fact, if you set your
pointers to 0 all the time then some bugs will never bite you that
otherwise would have taken hours or days to debug. Deleting a 0
pointer is not an error, deleting any other pointer that has been
deleted already is and can be one of the most difficult types of errors
to track down.

It is one minor step you can use to help you keep bugs out of your
programs. Scope isn't the issue, getting in the habit of ALWAYS doing
it benefits you in numerous ways.


Also notice that the reset will not always prevent the error. Actually,
I believe that it will do so only in the most trivial of situations.
The OPs problem would not be solved by setting the pointer to 0, for
example.

/Peter

Apr 11 '06 #35

P: n/a
Ian Collins wrote:
I'm not supporting the assert alternative


There never was an assert() alternative. The question was raised why
advanced programmers were not simply declaring all dead pointers should be
NULLed. I brought in NullObjects as an advanced alternative. The assert()
was to prevent nitpicking. A better implementation would hide the pointer,
and its assertions, and pass around a reference.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 11 '06 #36

P: n/a

peter koch wrote:
Noah Roberts skrev:
C. J. Clegg wrote:
On Mon, 10 Apr 2006 13:58:52 GMT, Joe Van Dyk <jo********@boeing.com>
wrote:

>> When you delete a pointer, you should set it to NULL, right?

You don't HAVE to.
doesn't hurt and is often helpful.

It is not always helpful. Also the ptr = 0 sends the wrong message to
the reader - is the pointer reset now and then or what is it that takes
place.


ptr = 0 is well defined. Everyone that is familiar with the language
knows exactly what it does.
And there it is. There is no reason NOT to beyond linespace fetishes.


There is one very good reason: to verify your program logic. Accessing
a resource that is no longer present is an obvious programming error,
and setting the pointer to 0 might just prevent that situation from
being identified.


Not true.
If you are going to set the pointer to anything, it is a far better
idea to set it to some illegal value the same way as operator delete
sets memory to an often illegal pattern in some debug builds.
This idea is very non-portable for one and doesn't follow standard
practice. Talk about being difficult to understand...

There is absolutely no reason to go looking for some other value to set
a pointer to. All that does is introduce problems in both
understandability, platform dependance, and undefined behavior.
If the pointer is used to designate an optional value, the situation is
different and you should set the pointer to 0.
It can save from hours to days debugging. In fact, if you set your
pointers to 0 all the time then some bugs will never bite you that
otherwise would have taken hours or days to debug. Deleting a 0
pointer is not an error, deleting any other pointer that has been
deleted already is and can be one of the most difficult types of errors
to track down.

It is one minor step you can use to help you keep bugs out of your
programs. Scope isn't the issue, getting in the habit of ALWAYS doing
it benefits you in numerous ways.


Also notice that the reset will not always prevent the error. Actually,
I believe that it will do so only in the most trivial of situations.
The OPs problem would not be solved by setting the pointer to 0, for
example.


The problem of deleting a pointer that was already deleted, the problem
I was talking about in the quote above, will ALWAYS be solved by
setting the pointer's value to 0. No other access can be solved in
this manner beyond the fact that you can now check the pointer's value
before accessing it...just as delete does.

Apr 11 '06 #37

P: n/a

Phlip wrote:
Ian Collins wrote:
I'm not supporting the assert alternative


There never was an assert() alternative. The question was raised why
advanced programmers were not simply declaring all dead pointers should be
NULLed. I brought in NullObjects as an advanced alternative. The assert()
was to prevent nitpicking. A better implementation would hide the pointer,
and its assertions, and pass around a reference.


Dude, the null object pattern has its place, and it isn't _everywhere_.

Apr 11 '06 #38

P: n/a

"Phlip" <ph******@yahoo.com> wrote in message
news:2h*****************@newssvr33.news.prodigy.co m...
Ian Collins wrote:
I'm not supporting the assert alternative


There never was an assert() alternative. The question was raised why
advanced programmers were not simply declaring all dead pointers should be
NULLed.


Phlip,

If you're referring to my statement "I'm a little surprised at the responses
you've been getting from some very experienced programmers.", what I meant
was that I'm surprised that in response to a very specific question the
replies were "smart pointer" and some guesses about what the pointer is
actually pointing at. I'm not at all surprised that experienced programmers
would not advocate "set all dead pointers to NULL." Over the years I've come
to the conclusion that mindlessly adding good- practice code snippets can do
more harm than good.

Andrew
Apr 11 '06 #39

P: n/a

Noah Roberts skrev:
peter koch wrote:
Noah Roberts skrev:
C. J. Clegg wrote:
> On Mon, 10 Apr 2006 13:58:52 GMT, Joe Van Dyk <jo********@boeing.com>
> wrote:
>
> >> When you delete a pointer, you should set it to NULL, right?
>
> You don't HAVE to.
> doesn't hurt and is often helpful.
It is not always helpful. Also the ptr = 0 sends the wrong message to
the reader - is the pointer reset now and then or what is it that takes
place.


ptr = 0 is well defined. Everyone that is familiar with the language
knows exactly what it does.

Surely, But the reader asks "why" and thats a different question to
answer.
And there it is. There is no reason NOT to beyond linespace fetishes.
There is one very good reason: to verify your program logic. Accessing
a resource that is no longer present is an obvious programming error,
and setting the pointer to 0 might just prevent that situation from
being identified.


Not true.

Sure? Examples given in this thread would specifically behave that way.
Far to often you write if (p != 0) p->action() instead of assert(p !=
0); p->action();
If you are going to set the pointer to anything, it is a far better
idea to set it to some illegal value the same way as operator delete
sets memory to an often illegal pattern in some debug builds.
This idea is very non-portable for one and doesn't follow standard
practice. Talk about being difficult to understand...

There is absolutely no reason to go looking for some other value to set
a pointer to. All that does is introduce problems in both
understandability, platform dependance, and undefined behavior.

That is a small problem as this is only something to do while
debugging.
If the pointer is used to designate an optional value, the situation is
different and you should set the pointer to 0.
It can save from hours to days debugging. In fact, if you set your
pointers to 0 all the time then some bugs will never bite you that
otherwise would have taken hours or days to debug. Deleting a 0
pointer is not an error, deleting any other pointer that has been
deleted already is and can be one of the most difficult types of errors
to track down.

It is one minor step you can use to help you keep bugs out of your
programs. Scope isn't the issue, getting in the habit of ALWAYS doing
it benefits you in numerous ways.


Also notice that the reset will not always prevent the error. Actually,
I believe that it will do so only in the most trivial of situations.
The OPs problem would not be solved by setting the pointer to 0, for
example.


The problem of deleting a pointer that was already deleted, the problem
I was talking about in the quote above, will ALWAYS be solved by
setting the pointer's value to 0. No other access can be solved in
this manner beyond the fact that you can now check the pointer's value
before accessing it...just as delete does.

Right. But that is a trivial situation - in all respects. Typically you
instead have two pointers pointing to the same object and delete one of
these. A problem that can't be solved without using smart pointers (or
discipline).

/Peter

Apr 11 '06 #40

P: n/a

peter koch wrote:
Noah Roberts skrev:
peter koch wrote:
Noah Roberts skrev: > And there it is. There is no reason NOT to beyond linespace fetishes.

There is one very good reason: to verify your program logic. Accessing
a resource that is no longer present is an obvious programming error,
and setting the pointer to 0 might just prevent that situation from
being identified.
Not true.

Sure? Examples given in this thread would specifically behave that way.
Far to often you write if (p != 0) p->action() instead of assert(p !=
0); p->action();


How are you applying logic here?

1) what example of pointer access would work if ptr is 0 and not
otherwise?
2) what is the relevance of the assert statement you make above?
If you are going to set the pointer to anything, it is a far better
idea to set it to some illegal value the same way as operator delete
sets memory to an often illegal pattern in some debug builds.


This idea is very non-portable for one and doesn't follow standard
practice. Talk about being difficult to understand...

There is absolutely no reason to go looking for some other value to set
a pointer to. All that does is introduce problems in both
understandability, platform dependance, and undefined behavior.

That is a small problem as this is only something to do while
debugging.


Yes, it is good to introduce hard to read, platform dependant,
undefined behavior during debugging and then replace it with different
code on release.

The arguments against setting a pointer to 0 after deletion just keep
getting dumber and dumber...I don't really find that surprising.

Apr 11 '06 #41

P: n/a
Noah Roberts wrote:
The arguments against setting a pointer to 0 after deletion just keep
getting dumber and dumber...I don't really find that surprising.


Smart code...

- uses smart pointers
- uses references
- use objects with fail-safe behaviors
- reduce 'if' statements on types*
- practices RAII
- generally only delete pointers about to go out of scope
- assign NULL to the tiny fraction of remaining pointers

*If I said "NULL is a type" here, I would get an entire thread of yacking
"NULL is a macro typically defined as 0 which is an integer,
blah-blah-blah". The book Design Patterns calls this topic "program to the
interface". Checking a pointer for NULL is a sign the design could be
generally better. It's using the interface to a pointer instead of an
interface to an object.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 11 '06 #42

P: n/a
Joe Van Dyk wrote:
Victor Bazarov wrote:
class B {
public:
void foo(A* aptr);

private:
A* aptr_;
};

void B::foo(A* aptr)
{
aptr_ = aptr;
}

B::~B()
{
delete aptr_;
}


OK, this is the case where setting aptr_ to NULL won't have any effect
because B (hence aptr_) is itself being destroyed. (Assuming that it
isn't B that is getting destroyed twice.)

The bug is that B::foo requires an A object that it can own, and delete,
and doesn't have a name/comment/document making that obvious to you.

No doubt you have passed the same A to multiple calls of B::foo, or
kept the A pointer and eventually deleted it, which would be the right
thing to do if B::foo did not have this undocumented requirement.
Apr 12 '06 #43

P: n/a
Robert Mabee wrote:
The bug is that B::foo requires an A object that it can own, and delete,
and doesn't have a name/comment/document making that obvious to you.


It would be nice we could indeed make that problem a "bug". std::auto_ptr
can only get as far as making its constructor explicit, which is as much a
nuisance as a compilable comment. ;-)

Nice thread busting on the evils of RAII, guys...

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 12 '06 #44

P: n/a
Victor Bazarov wrote:
Phlip wrote:
If you must, use std::auto_ptr or boost::shared_ptr, and reset(NULL)
that (if I recall correctly).


'boost' is non-standard. 'std::auto_ptr' is not suitable for some
cases due to its particular copy semantics.


No reason not to use boost. Besides, boost smart pointers have been accepted
into TR1, so they are standard and will be supported by newer compilers.

--
Paul M. Dubuc
Apr 12 '06 #45

P: n/a
Paul M. Dubuc wrote:
No reason not to use boost.


Also no reason not to suggest or (lightly) discuss Boost here.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 12 '06 #46

P: n/a

Paul M. Dubuc wrote:
Victor Bazarov wrote:
Phlip wrote:
If you must, use std::auto_ptr or boost::shared_ptr, and reset(NULL)
that (if I recall correctly).


'boost' is non-standard. 'std::auto_ptr' is not suitable for some
cases due to its particular copy semantics.


No reason not to use boost. Besides, boost smart pointers have been accepted
into TR1, so they are standard and will be supported by newer compilers.


wrong.

"This technical report is non-normative. Some of the library components
in this technical report may be considered for standardization in a
future version of C++, but they are not currently part of any C++
standard. Some of the components in this technical report may never be
standardized, and others may be standardized in a substantially changed
form."

Apr 12 '06 #47

P: n/a
Phlip wrote:
Paul M. Dubuc wrote:
No reason not to use boost.


Also no reason not to suggest or (lightly) discuss Boost here.


Do you apply that to all non-standard, third-pary libraries?

Brian
Apr 12 '06 #48

P: n/a
Default User wrote:
Also no reason not to suggest or (lightly) discuss Boost here.


Do you apply that to all non-standard, third-pary libraries?


Specific questions about some library X belong on X's forum.

The general question "what [portable] C++ library does X" belong in
the best platform-neutral C++ forum possible.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 12 '06 #49

P: n/a
Default User wrote:
Phlip wrote:
Paul M. Dubuc wrote:
> No reason not to use boost.


Also no reason not to suggest or (lightly) discuss Boost here.


Do you apply that to all non-standard, third-pary libraries?


Topicality, as per our FAQ, includes planned extensions to the standard. Can
you get any closer than tr1? Even though not everything in boost is up for
standardization, boost happens to be the default route of an idea into the
standard. I consider that topical.
Best

Kai-Uwe Bux

Apr 13 '06 #50

51 Replies

This discussion thread is closed

Replies have been disabled for this discussion.