tags:

views:

608

answers:

11

This came up as one of the code review comments.

Is it a good idea to check for NULL before calling delete for any object?

I do understand delete operator checks for NULL internally and is redundant but the argument put forth was delete as an operator can be overloaded and if the overloaded version doesnt check for the NULL it may crash.So is it safe and reasonable to assume that if and when delete will be overloaded it will check for the NULL or not? In my understanding its reasonable to assume the first case that overloaded delete shall take care of the NULL check, and the review point doesnt hold good.What do you think?

+21  A: 

No, don't check for null. Standard says that delete (T*)0; is valid. It will just complicate your code for no benefits. If operator delete is overloaded it's better to check for null in the implementation of the operator. Just saves code lines and bugs.

ybungalobill
so does it mean incase of overloaded `operator delete` the responsibilty of conforming with the standard lies in the implementation of the operator ? i.e. if it doesn't check for NULL then it is not conforming to the standard?
Naveen
@Naveen - That is the question I am trying get an answer to, Thanks for bringing it out with right words!
Als
@Naveen @Als: Yes in weak sense. No in the strong sense of the word "conforming". If you implement operator delete that doesn't check for NULL it's still conforming (e.g. it just prints `cout << address << '\n'`). But if it brings undefined behavior it's a bug in your `operator delete` implementation.
ybungalobill
@ybungalobill: It is non conforming in all senses. A conforming implementation of `delete` must be able to handle 0 as an argument. There is no way to consider something to be *conforming* if for a well defined operation it yields undefined behavior. Conformance is not only at the interface level, it is not just that the arguments match, but the semantics must be the same.
David Rodríguez - dribeas
@David: Please read ybungalobill's comment fully---it _can_ be conforming if it doesn't invoke UB. For example: placement `delete` doesn't do anything with its argument (at all), so, it doesn't need to check for null either.
Chris Jester-Young
@David @Chris Sorry, what I said is actually partially nonsense. What I answered was the question stated as "if it doesn't check for NULL then it is not conforming". Well it can be conforming without checking for null.
ybungalobill
@Chris Jester-Young: *placement delete*??
David Rodríguez - dribeas
@David: So, with custom `new` operators, you can (and should) define corresponding custom `delete` operators, so that if the construction of the object fails, the allocated memory can be deallocated. Placement `delete` corresponds to placement `new` (which, of course, also does nothing except return the given pointer).
Chris Jester-Young
@Chris Jester-Young: To quote the standard in 18.4.1.3 **Placement forms**: *"These functions are reserved, a C++ program may not define functions that displace the versions in the Standard C++ library (17.4.3). The provisions of (3.7.3) do not apply to these reserved placement forms of operator new and operator delete."* That is, you cannot *displace* (override/replace) the placement forms, and that means that you cannot possibly provide a *conforming* implementation that does not check null (nor one that does check).
David Rodríguez - dribeas
@David: Right, I wasn't suggesting to make a placement `delete` yourself, but using it as a counterexample for the "must check null or is non-conformant" statement.
Chris Jester-Young
The thing is that there are different things that are all called `new`/`delete`, and the only one that you can *displace* is the allocator version of it. In that case, the user provided `delete` must be able to handle 0 as argument (note that as in the initial comment I am not saying *check for 0*, but that it must be able to handle that value passed as argument).
David Rodríguez - dribeas
@David: as @ybungalobill stated, checking for NULL isn't required not to trigger UB. Therefore checking for NULL is not required to be conforming, all that is required is that it works with NULL.
Matthieu M.
@Matthieu M.: I agree, either I misunderstood or I have failed to be clear in my writing. Caller does not need nor should check for null. User implementation of `delete` must be able to handle `0` properly without triggering UB to be conforming.
David Rodríguez - dribeas
+15  A: 

I would say that that's more a reason to ensure that if you overload operator delete, then you should always have it check for NULL, otherwise you're breaking the semantics.

Oli Charlesworth
+7  A: 

Is it a good idea to check for NULL before calling delete for any object?

No!

int *p = NULL;
delete p ; //no effect

The Standard says [Section 5.3.5/2]

If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section. In either alternative, if the value of the operand of delete is the null pointer the operation has no effect.

Furthermore in Section 18.4.1.1/13

void operator delete(void* ptr) throw();

void operator delete(void* ptr, const std::nothrow_t&) throw();

Default behavior:

For a null value of ptr, do nothing.

— Any other value of ptr shall be a value returned earlier by a call to the default operator new, which was not invalidated by an intervening call to operator delete(void*) (17.4.3.7). For such a non-null value of ptr, reclaims storage allocated by the earlier call to the default operator new.

EDIT :

James Kanze here says that

It's still the responisiblity of operator delete (or delete[]) to check; the standard doesn't guarantee that it won't be given a null pointer; the standard requires that it be a no-op if given a null pointer. Or that the implementation is allowed to call it. According to the latest draft, "The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect." I'm not quite sure what the implications of that "is one supplied in the standard library" are meant to be---taken literally, since his function is not one provided by the standard library, the sentence wouldn't seem to apply. But somehow, that doesn't make sense.

Prasoon Saurav
-1 read the question.
wilhelmtell
@wilhelmtell : Can't you see a big **NO**?
Prasoon Saurav
I can, but your reasoning obviously shows you stopped reading at the question's title. The OP *KNOWS* this is a noop in the default case.
wilhelmtell
@wihelmtell : No I didn't stop after reading the question's title. That's why I have linked the `bytes.com` thread and asked him to read James Kanze's answer.
Prasoon Saurav
+2  A: 

No need to check null. delete operator does chck for null so additional check is not required.

+2  A: 

delete (T*)0; is valid and does nothing, similarly free(NULL); is also valid and does nothing. If you overload the delete operator, your implementation should carry the same semantics. The standard says how the standard delete will work, but I don't think it says how an overloaded delete should behave. For the sake of consistency with the standard/default behaviour, it should allow (T*)0 as input.

dreamlax
+2  A: 

From Standard docs, 18.5.1.1.13 under delete,

Default behavior: If ptr is null, does nothing. Otherwise, reclaims the storage allocated by the earlier call to operator new.

So, you don't have to check by default..

liaK
A: 

No need to check for NULL prior to deleting. If someone has overloading delete with something that does not behave in a standard way then that's the real problem. No-one should take lightly the task of overloading delete and should always support expected behaviour such as checking for NULL and taking no action.

However, for what it's worth, you should always remember to assign zero to any pointer that you've just deleted, unless for example you are about to delete the pointer as well:

void MyObj::reset()
{
    delete impl_;
    impl_ = 0;    // Needed here - impl_ may be reused / referenced.
}

MyObj::~MyObj()
{
    delete impl_; // No need to assign here as impl_ is going out of scope.
}
Robin Welch
+5  A: 

I would say it is the responsibility of an overloaded delete to behave like you expect delete to behave. That is, it should handle NULL pointers as a no-op.

And so, when calling an overloaded delete, you should not check for NULL. You should rely on the overloaded delete to be implemented correctly.

jalf
A: 

A bit of C++ pedantry: NULL is not a built-in concept. Yes we all know what it means but in C++ before C++0X the null pointer concept is simply the value 0. NULL is usually a platform-specific macro that expands to 0.

With C++0X we're getting nullptr which is clearer than a plain zero and is not convertible to any integral type except bool, and is a better concept than NULL (or perhaps a better implementation of the concept behind NULL).

MadKeithV
Alternatively, a lot of C++ pedantry: a null pointer is the value "a null pointer", not (necessarily) the value 0, which is an integer, not a pointer. When converted to a pointer type, a *constant* integer expression with value 0 results in a null pointer (and hence is called a "null pointer constant"), but that's a special case defined in the standard.
Steve Jessop
Well since the only way to define a null pointer through the language prior to C++0X is to use the constant value literal 0 and that results in calling the integer overload rather than the pointer overload, that is REALLY pedantic ,-)
MadKeithV
@MadKeith: There are other ways to get a null pointer. For example, `std::strstr("a","b");`. Obviously, using a null pointer constant is the *sensible* way. My bonus pedantry is just to point out that there's a difference between `0` (an integer, and a null pointer constant, and a possible value for NULL) vs `(char*)0` or `(void*)0` (both null pointers, and both null pointer constants, but neither is legal for NULL in C++).
Steve Jessop
+1  A: 

Is it not necesary to check. If anyone overload the pethod, is his responsibility to to whatever with NULL.

greuze
A: 

I would say the questions contains incomplete information. My shop still has a check for NULL before delete in our coding standard, as we still have one compiler/platform configuration that we must support that goes into undefined behavior with the defualt delete operator if it is passed NULL. If the original poster has a simular situation then there is a point to the check for NULL, otherwise, change the coding standard!

diverscuba23
@diverscuba23 - Sorry, No my platform does not have any such limitation, but assuming one always write a portable code delete implementation will have to be overloaded most of the times(memory leak detection based logging, special memory implementations etc) so the question still holds good doesnt it?
Als
@Als The compiler/platform configuration will go into undefinded behaviour for even built-in types (i.e. int, char, etc) as it really is a bug with the platforms free() implementation, but there have been no fixes for it as it is a dead platform.
diverscuba23