Is it safe to delete a NULL pointer?
Asked Answered
C

9

352

Is it safe to delete a NULL pointer?

And is it a good coding style?

Career answered 16/11, 2010 at 2:33 Comment(6)
Good practice is to write C++ programs without a single call to delete. Use RAII instead. That is, use std::vector<T> v(100); instead of T* p = new T[100];, use smart pointers like unique_ptr<T> and shared_ptr<T> that take care of deletion instead of raw pointers etc.Isopropyl
thanks to make_shared (c++11) and make_unique (c++14) your program should contain zero of new and deleteKnob
There may still be some rare cases that require new/delete, eg atomic<T*>: atomic<unique_ptr<T>> isn't allowed and atomic<shared_ptr<T>> has overhead that may be unacceptable in some cases.Slipcover
To declare a class with resource management using RAII you need to call new and delete right?, or you are saying there is some template class to hide this even this.Demote
@Demote The point is that most user/client (that is: non-library) code should never have to write new or delete. Classes designed to manage resources, where Standard components can't do the job, can of course do what they need to do, but the point is that they do the ugly stuff with the memory they manage, not the end-user code. So, make your own library/helper class to do new/delete, and use that class instead of them.Housekeeping
Possible duplicate of Is there any reason to check for a NULL pointer before deleting?Housekeeping
A
313

delete performs the check anyway, so checking it on your side adds overhead and looks uglier. A very good practice is setting the pointer to NULL after delete (helps avoiding double deletion and other similar memory corruption problems).

I'd also love if delete by default was setting the parameter to NULL like in

#define my_delete(x) {delete x; x = NULL;}

(I know about R and L values, but wouldn't it be nice?)

Alarice answered 16/11, 2010 at 2:38 Comment(33)
Note that there still can be several other pointers pointing to the same object even if you set one to NULL on deletion.Flem
@Flem sure, but it's still better than nothing. In most cases there is only one pointer.Alarice
In most cases in my code, the pointer goes out of scope once it's been deleted. Much safer than merely setting it to NULL.Algology
what about them? They're typically smart pointers, or they're members of my own ad hoc RAII class, which, like I said, goes out of scope when the pointer is deleted -- or they point to an object whose lifetime extends past that of the object containing the pointer.Algology
@ruslik: Class members go out of scope when the containing object goes out of scope. Hence, in the dtor, there's no point in setting them to zero. Now, in an assignment operator, it may be necessary to delete a pointer to a subobject, but only if you already have a new suboject ! It's not exception-safe to delete the old object first - you could end up with no subobject at all. Therefore, you wouldn't set the pointer to NULL; you'd set it to the new object.Beaverbrook
@ruslik: raw pointer members are an extremely bad idea in modern C++.Isopropyl
A very god practice is not setting the pointer to NULL after delete. Setting a pointer to NULL after deleting it masquerades memory allocation errors, which is a very bad thing. A program that is correct does not delete a pointer twice, and a program that does delete a pointer twice should crash.Teirtza
@Teirtza A program that deletes a pointer set to an object, and then deletes a pointer set to NULL, is correct. That's what the standard says.Isolation
@Alice: It is irrelevant what the standard says in that respect. The standard defined deleting a null pointer being valid for some absurd reason 30 years ago, so it is legal (most likely a C legacy). But deleting the same pointer twice (even after changing its bit pattern) is still a serious program error. Not by the wording of the standard, but by program logic and ownership. As is deleting a null pointer, since the null pointer corresponds to no object, so nothing could possibly be deleted. A program must exactly know if an object is valid and who owns it, and when it can be deleted.Teirtza
@Alice: Worded differently, this unlucky rule of the standard allows for programs that behave erroneously (hopefully I spelled that right) to execute as-if correct. When in fact, the validity and ownership of objects isn't clear at all (you could say it's guesswork). It only works by accident because the problem is silently ignored. A better approach would be to crash early (or throw, if you will), which forces the developer to make sure the program's logic is correct. Setting a pointer to (T*)1 instead of nullptr will do that, it will crash hard if you try to delete it again.Teirtza
@Teirtza The correctness of a program is dictated by if a programs behavior is correct with respect to a specification. Part of that spec is user related (does the code do what I want) and part is standards related (does it follow the rules of the language). In both cases, a program which frees a NULL is correct; it follows the rules of the language, and causes no errors. It does not work "by accident"; this was discussed, and included into the standard, not merely as legacy but because it is useful and removes checks for NULL in areas where they are pointless. It works as C++ was designed.Isolation
@Teirtza You are imposing your own beliefs onto the area of code correctness: pointers represent a weak reference option type, with NULL indicating no value. Deleting on an option type should be, by type theory, defined for the optional part as well; otherwise it's not optional. So, you must be able to safely delete NULL; otherwise, you break the type contract, and therefore have no way to prove correctness. Ownership is irrelevant: pointers are weak for a reason, use shared_ptr if that's your use case. A program need not know ownership exactly; it need only not undermine it's constraints.Isolation
@Alice: C++ was standardized 8 years after being invented by a single person. The standard committee had to assure above all one thing: Making sure that the vast majority of code that relied on this mis-feature did not break. Insofar there was no real "decision". Your interpretation of the standard is of course correct, but it is pedantic. A program that does not know when an object is valid is incorrect. Resource ownership is not gambling or looking in a crystal ball or something you leave to chance otherwise. It is something that is unambiguous and well-defined in a well-written program.Teirtza
@Teirtza First, that isn't true; the standard made several changes that caused a vast majority of code to break. See the history of the STL for details. Second, program correctness does not exist in a vacuum; you must prove a program correct against a specification. Well definedness has a specification: does the program do the same thing each time it runs with the same values? Finally, ambiguity means two equally valid results come from the same values. Correctness implies well defined, which implies ambiguity. None of these in any way deal with knowing whether an object is valid.Isolation
@Teirtza Deleting a NULL is not ambiguous; it does the same thing every time. It is well defined; the specification exists and says what it does, and it does the same thing every time. And it is correct; both the IO of the program match spec, and it matches type theories spec on optional types. Furthermore, object validity has no impact on any of these; weak pointers may point to valid or invalid objects, but are not ambiguous, ill defined, or incorrect. And without extra work, it is impossible to prove if they are valid or not; it is unknowable. Is any C++ program with raw pointers incorrect?Isolation
@Alice: You don't get it. If you have a pointer, this pointer is either uninitialized/invalid, or it points to an object (without owning it), or it owns an object. No matter what, this is something that must be exactly and unambiguously known at all times. There is exactly one instance, the owning pointer, which is allowed (and required) to delete the object at a well-defined time. If that is not the case, your program logic is wrong. Deleting NULL being legal and setting invalid pointers to that value hides this problem. It makes programs that don't get ownership right "well behaving".Teirtza
@Teirtza What you said is just false. Suppose I have a raw pointer to some object, as does some framework (this occurs often in QT, WT, etc). The framework deletes that object, possibly in response to code I have no control over. Now I have a pointer to an invalid object, but I don't know it's invalid (and in fact, can't know, as much of the code I am linking is beyond my control). Furthermore, no notion of an owning pointer exists; all pointers can delete the object they point to, and none are required to; it's perfectly valid to allow the heap to clean up trivial objects on program close.Isolation
@Teirtza The flaw here is that you have a draconian view of ownership that neither the standard, type theory, or logic in general require. Each of your "requirements" can be overturned with no loss of correctness; multiple pointers may delete, no pointers need own, the time of delete need not be well defined, and weak pointers need not know the object they point to is invalid. But none of that has to do with deleting NULL being legal or setting pointers to NULL to hide double free's; in fact doing so enhances correctness, because it means programs do not exhibit incorrect or undefined behavior.Isolation
@Alice: I wish you good luck for the future as several threads of exectuion are becoming (or in fact are already) the norm, not the exception. Ideas like "any pointer can delete" or "ownership and time of deletion needs not be well-defined" will help you a great deal writing robust programs and will earn you a lot of love among your co-workers.Teirtza
@Teirtza I'm a maintainer of several lock free structures, and attempting to publish a paper on a novel lock free trie. One of the main characteristics of a lock free structure is that a thread may need to help another thread, rather than progress in its own right. This often necessitates several pointers each capable of deleting. This is, in fact, provably true for some algorithms on hardware with only CAS, not DCAS (most commercial hardware). As well, the time when deletes can occur in such scenarios are often not well defined, in the sense they will not occur at the same time each execution.Isolation
@Teirtza However, despite these abrogations of your draconian ownership rules, lock free structures are provably more robust than lock based ones. And yes, my co-workers do indeed love me for the enhanced execution profile these structures provide and the rigorous thread safety they maintain, which allow easier to reason about code (great for maintenance). However, none of this nor your implied personal attack have to do with any definition of correctness, validity, or ownership. What you propose is a good rule of thumb, but it is not a universal law nor is it enshrined in the standard.Isolation
"I know about R and L values" -- But apparently you don't know about references. <template T> void my_delete(T*& p) { delete p; p = NULL; }Luminal
@Isolation "weak pointers need not know the object they point to is invalid" -- they do if they can be deleted; in that case they need a reference count to avoid multiple deallocation. " But none of that has to do with deleting NULL being legal or setting pointers to NULL to hide double free's" -- More likely a pointer is set to NULL after delete to return it to a "reset" state. This is a perfectly valid semantics, and was in use long before owned pointers ... which have a memory cost that Damon seems unaware of. There are still machines with finite memory where such things matter. :-)Luminal
JimBalter That is an excellent point that @Teirtza also seems unaware of: constraints have costs, and C deliberately avoids many constraints explicitly because of the costs involved. Deleting a NULL is entirely justifiable if it makes an otherwise slow concept of ownership faster with no loss of safety (which is demonstrably true in many cases). Why use a slower mechanism for safety if it provides no benefits?Isolation
If reuse of stale pointers was always guaranteed to lead to an immediate crash, I might agree with @Damon's recommendation. But memory gets reused, in both predictable (stack) and unpredictable (heap) locations. And non-null pointers can get passed around and copied many times before they get dereferenced, producing hidden aliasing and Heisenbugs of various flavors far from the site of the original problem. Having had to debug a few of these bugs over the course of my career, I am a firm believer in resetting stale pointers to NULL as soon as possible, as a basic sanitation move.Symer
@Alice: I know it's been some time, but I'm interesting in reading your paper on lock free tries, and also wondering if you had a github or similar for your other lock free structures?Plaster
I wonder where the "move to chat" suggestion went in this comment thread...Elis
@Teirtza Totally agree. Setting a pointer to nullptr can can also have important performance implications. For example, if you have a tree data structure and rely on recursion for deletion and decide to set a pointer to nullptr after calling delete, the stack frames cannot be reused as in tail recursion. It can many times be enough to cause a stack overflow if you set a pointer to nullptr after deleting.Tham
NOTE: Using a MACRO will cause double evaluation if an expression is used. example: my_delete(Order3PizzasAndBurnTheBakery())Dumps
@Dumps this example is invalid. Macro argument need to be an lvalue, and function call isn't, so it won't compile. But you've got the point. For function int** foo(void){static int *arr = new int(4); return &arr;} calling my_delete(*foo()) will allocate, delete, then allocate again and finally nullify arr (no pointers to allocated memory - memory leak). On the other hand my_delete(x) {auto _tmp = &(x); .. will fail if x is direct function call (not an lvalue). I wonder why such error-prone code is in accepted answer.Premillennialism
@Premillennialism "Macro argument need to be an lvalue" ...What? That is trivially false. Macros don't know anything about value categories, objects, or any language features; they are just brainless substitution devices. A macro argument containing the textual representation of a function call or any other expression will be substituted into the body of the macro however many times that argument occurs, and so the expression will be evaluated - and the function called - that many times, regardless of what the function call returns or what value category that has.Housekeeping
@Housekeeping you've taken my words out of context, perhaps my wording wasn't the best one. Look at definition of 'my_delete' - after macro expansion there is assignment to macro argument. You are correct about macro preprocessor being simply textual mechanism that will just copy-paste the definition, but resultant code will be incorrect (at compile time).Premillennialism
@Teirtza "pointer is either uninitialized/invalid, or it points to an object (without owning it), or it owns an object." That's just not true. A pointer can be initialized and not point to an object. For example it can be initialized to 0. Like how most event handler callback function pointers are initialized! (Of course you wouldn't call delete on them.) You can also have pointers to dynamically allocated buffers, arrays that you may or may not need and only allocate them on demand runtime, and instead of "allocating 0 size" you set them to null. Setting pointer=0 signals they point to nothing.Hydrometallurgy
P
89

From the C++0x draft Standard.

$5.3.5/2 - "[...]In either alternative, the value of the operand of delete may be a null pointer value.[...'"

Of course, no one would ever do 'delete' of a pointer with NULL value, but it is safe to do. Ideally one should not have code that does deletion of a NULL pointer. But it is sometimes useful when deletion of pointers (e.g. in a container) happens in a loop. Since delete of a NULL pointer value is safe, one can really write the deletion logic without explicit checks for NULL operand to delete.

As an aside, C Standard $7.20.3.2 also says that 'free' on a NULL pointer does no action.

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs.

Pedometer answered 16/11, 2010 at 2:38 Comment(2)
I would really like this answer for its citations if it didn't intentionally introduce inefficiency in non-optimized code. As the accepted answer states, deletion of a null pointer is a no-op. Therefore, checking if a pointer is null before deleting it is completely extraneous.Concordance
Deleting a pointer to NULL is a perfectly reasonable thing to do in at least one case: when NULL indicates a resource was never allocated in the first place (but could have been) and where external constraints (e.g. the need to let a C API own the resource) prevent using RAII.Aileen
A
56

Yes it is safe.

There's no harm in deleting a null pointer; it often reduces the number of tests at the tail of a function if the unallocated pointers are initialized to zero and then simply deleted.


Since the previous sentence has caused confusion, an example — which isn't exception safe — of what is being described:

void somefunc(void)
{
    SomeType *pst = 0;
    AnotherType *pat = 0;

    …
    pst = new SomeType;
    …
    if (…)
    {
        pat = new AnotherType[10];
        …
    }
    if (…)
    {
        …code using pat sometimes…
    }

    delete[] pat;
    delete pst;
}

There are all sorts of nits that can be picked with the sample code, but the concept is (I hope) clear. The pointer variables are initialized to zero so that the delete operations at the end of the function do not need to test whether they're non-null in the source code; the library code performs that check anyway.

Analyzer answered 16/11, 2010 at 2:35 Comment(3)
I had to read that a few times to make sense of it. You must mean initializing them to zero at the top of the method, or during it, not at the tail, surely? Otherwise you would just remove both the zeroing and the delete.Glide
@EJP: A not wholly implausible outline of a function might be: void func(void) { X *x1 = 0; Y *y1 = 0; … x1 = new[10] X; … y1 = new[10] Y; … delete[] y1; delete[] x1; }. I've not shown any block structure or jumps, but the delete[] operations at the end are safe because of the initializations at the start. If something jumped to the end after x1 was allocated and before y1 was allocated and there was no initialization of y1, then there'd be undefined behaviour — and while the code could test for nullness (of x1 and y1) before the deletions, there is no need to do so.Analyzer
It's nice to know it is safe. But one might nevertheless use a "if (mypointer)" clause because it signals to someone reading the code that the pointer in question is one that might not have been set, and it signals that this is not a bug or an awkwardness but part of the design (I admit a comment could also be used).Svend
J
22

Deleting a null pointer has no effect. It's not good coding style necessarily because it's not needed, but it's not bad either.

If you are searching for good coding practices consider using smart pointers instead so then you don't need to delete at all.

Jehius answered 16/11, 2010 at 2:35 Comment(4)
the time people want to delete a NULL pointer is when they're not sure if it contains NULL... if they knew it was NULL then they wouldn't be considering delete and hence asking ;-).Mastersinger
@Tony: My point was only that it will have no effect, and the presence of such code which deletes a pointer which sometimes contains NULL is not necessarily bad.Jehius
IMO redundant checks certainly are bad, for performance, readability and maintainability.Nambypamby
@Nambypamby OP is certainly not talking about that kind of bad, more of Seg Fault / UB kind of bad.Pathe
R
16

To complement ruslik's answer, in C++14 you can use this construction:

delete std::exchange(heapObject, nullptr);
Raddatz answered 8/11, 2017 at 15:1 Comment(0)
S
4

It is safe unless you overloaded the delete operator. if you overloaded the delete operator and not handling null condition then it is not safe at all.

Spacesuit answered 16/11, 2014 at 11:15 Comment(1)
Could you add any explanation for your answer?Jealous
G
0

There is a FAQ on this matter which answers this question.

The C++ language guarantees that delete p will do nothing if p is null. Since you might get the test backwards, and since most testing methodologies force you to explicitly test every branch point, you should not put in the redundant if test.

Greyson answered 5/3, 2021 at 17:21 Comment(0)
G
0

It is safe and better practice to directly call delete without checking if it is null.

see https://clang.llvm.org/extra/clang-tidy/checks/readability/delete-null-pointer.html#:~:text=Checks%20the%20if%20statements%20where,null%20pointer%20has%20no%20effect.

Geranium answered 7/4, 2023 at 7:25 Comment(0)
A
-4

I have experienced that it is not safe (VS2010) to delete[] NULL (i.e. array syntax). I'm not sure whether this is according to the C++ standard.

It is safe to delete NULL (scalar syntax).

Algy answered 30/8, 2013 at 16:50 Comment(8)
This is illegal, and I don’t believe it.Edson
You should be able to delete any null pointer. So if it's breaking for you, then you probably have a bug in the code that shows it.Submissive
§5.3.2 In the second alternative (delete array), the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression.Knob
@KonradRudolph What's illegal?Astronomy
@Astronomy The behaviour of VS2010 alleged in the answer. As explained in other comments, it's safe to delete[] NULL.Edson
@KonradRudolph Maybe, but VS is known for its quirks, so it's at least plausible.Astronomy
@Astronomy That's why I wrote “I don't believe it” rather than “that's wrong”. But I still don't, and it would be a pretty outrageous, stupid violation of the standard. VC++ is actually generally pretty good at following the standard's restrictions, and the places where it violates them make sense historically.Edson
Just checked in VS2010 - they both work fine with null: i.stack.imgur.com/Ug327.pngGereron

© 2022 - 2024 — McMap. All rights reserved.