Set a pointer to null when deleting?

N

Noah Roberts

Phlip said:
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.
 
A

andrew queisser

[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
 
A

andrew queisser

I've got an object (Object A) that contains two pointers to objects that
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
 
N

Noah Roberts

andrew said:
[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.
 
P

Phlip

Noah said:
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...
 
N

Noah Roberts

Phlip said:
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?
 
P

Phlip

Noah said:
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.
 
N

Noah Roberts

Phlip said:
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.


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.
 
O

Old Wolf

Phlip said:
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).
 
N

Noah Roberts

Old said:
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.
 
I

Ian Collins

Old said:
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.
 
N

Noah Roberts

Ian said:
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 -
 
P

peter koch

Noah Roberts skrev:
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
 
P

Phlip

Ian said:
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.
 
N

Noah Roberts

peter said:
Noah Roberts skrev:

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.
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.

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.
 
N

Noah Roberts

Phlip said:
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_.
 
A

andrew queisser

Phlip said:
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
 
P

peter koch

Noah Roberts skrev:
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.
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();
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.
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
 

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,769
Messages
2,569,582
Members
45,069
Latest member
SimplyleanKetoReviews

Latest Threads

Top