Set a pointer to null when deleting?

P

Phlip

Joe said:
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.
 
M

Michiel.Salters

Joe said:
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
 
V

Victor Bazarov

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

Victor Bazarov

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
 
J

Joe Van Dyk

Victor said:
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
 
C

C. J. Clegg

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

Joe Van Dyk

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

Noah Roberts

C. J. Clegg said:
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.
 
V

Victor Bazarov

Joe said:
[..]
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
 
N

Noah Roberts

Joe said:
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.
 
J

Joe Van Dyk

Phlip said:
Joe Van Dyk wrote:




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

Joe Van Dyk

Victor said:
Joe said:
[..]
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_;
};




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_;
}


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




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
 
A

andrew queisser

Joe Van Dyk said:
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
 
P

Phlip

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

Noah Roberts

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

Phlip

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

Noah Roberts

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

Phlip

The function is less complex. It formerly had a visible controlled
statement.
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/refactoring/nullObject.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. ;-)
 

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,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top