8

I have watched a talk in CPPCon which is back to basic: class layout and the link is this. At 54:20, he said it's undefined bahavior to delete the nullptr twice. As far as I know, C++ standard guarantee deleting a nullptr does nothing but why deleting a nullptr twice is undefined bahavior?

And I was told before that there is no need to check if ptr is null in destructor because deleting a null pointer is valid. But if delete a null pointer twice is undefined, does that mean I still need to check if it's nullptr to prevent double-deleting happen?

This is a transcription of the author from his video:

[...] ignore the standard and then got later problems. A common example I see is it's ok to delete a null pointer, that's fine, but you can't delete it twice without resetting the value to some valid pointer value. If I delete the same pointer twice if it's not null you'll get probably a segfault, if it is null it typically just happens to work, but it's not guaranteed to work and there was actually one compiler in the 1980s where it wouldn't work because when you deleted a pointer a new value was overwritten in the deleted pointer. So again, do follow the standard.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Kidsunbo
  • 1,024
  • 1
  • 11
  • 21
  • 2
    I don't see where he stated that deleting the null pointer twice is undefined behavior. All he has is a code snippet where he responsibly initialized the pointer to nullptr, with a bunch of `...` to indicate that the pointer eventually points to dynamic memory at some point. *Then* the deletion occurs twice of the same pointer value. – PaulMcKenzie Aug 28 '21 at 03:00
  • 3
    Don't believe everything you find on the internet. Deleting a nullptr does nothing, no matter how many times you do it. – Mark Ransom Aug 28 '21 at 03:01
  • In standard C++, `delete` has no effect on a null pointer. In some pre-standard implementations of C++ (in the early 90s, predating the first C++ standard that was ratified in 1998) a runtime crash could result. It is undefined behaviour to `delete` a non-null pointer twice (e.g. to destroy a dynamically allocated object twice) and a `delete` expression is not required to change the value of the pointer. – Peter Aug 28 '21 at 03:02
  • 1
    @PaulMcKenzie He said if it's null, it typically just happen to work but it's not guaranteed to work. And sorry for that if I make a misunderstanding because I am not a native speaker. – Kidsunbo Aug 28 '21 at 03:03
  • 1
    @Peter in fact I don't think it's even *allowed* for delete to change the value of a pointer. Certainly it would be surprising if it did. – Mark Ransom Aug 28 '21 at 03:04
  • @MarkRansom - Follow this link https://stackoverflow.com/questions/5002055/is-the-pointer-guaranteed-to-preserve-its-value-after-delete-in-c (look at the first answer) and enjoy being surprised. – Peter Aug 28 '21 at 03:05
  • 2
    @Peter I don't see anything at the link that contradicts what I said. You'll have to be more specific. – Mark Ransom Aug 28 '21 at 03:10
  • 1
    @MarkRansom "No, it's not guaranteed and an implementation may legitimately assign zero to an lvalue operand to delete." – Nathan Pierson Aug 28 '21 at 03:16
  • @Peter sorry, your first iteration of the comment directed me to a different place than the link you edited in. Yes, now I'm surprised. – Mark Ransom Aug 28 '21 at 03:20
  • @NathanPierson the original version of Peter's comment said to follow the link provided in one of the answers. That link was to cppreference.com and did not contain the text you quoted. – Mark Ransom Aug 28 '21 at 03:22
  • @MarkRansom Yeah, sorry about that. Copy and paste error on my part, which I edited a few seconds after. – Peter Aug 28 '21 at 04:02
  • `struct Foo{}; int main() { Foo* p = nullptr; delete p; p = nullptr; delete p; }` is well defined behavior. – Eljay Aug 28 '21 at 13:18
  • It sounds like the dude was talking about a compiler creating debug-mode code to help catch double deletes. If he didn't understand what was going on in that case I wouldn't put any stock in anything else he said. – HerrJoebob Aug 28 '21 at 16:15
  • Obviously, with just a bit of **common sense**, one can easily deduce that it is legal... If it is legal to delete a pointer to nullptr, then that pointer must still be nullptr afterward and thus be deleted again. – Phil1970 Aug 20 '22 at 22:18

3 Answers3

8

Is it safe to delete a nullptr twice in C++?

Yes (in all standard versions of C++). It is guarnteed to work (by work, I mean it doesn't do anyting).

Deletion has no effects if the argument is a null pointer. The compiler that the presenter describes did not conform to the C++ standard. The described compiler also was from the 80's, so it was made before C++ was standardised. The presenter is wrong in saying that you can't delete the null pointer twice if they are referring to standard C++ which does seem to be implied.

It is true that deletion may indirectly cause the program to behave as if the value of the argument pointer was changed (and by as-if rule that means that they effectively can change the value), but only in case where the pointer was non-null and is thus invalidated by the deletion. In fact, this allowance applies to all pointer objects that had the same value as all of them are thereby invalidated. This is because all ways that could observe the value of an invalid pointer are either undefined or implementation defined behaviour.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I added a transcription from the video. The author is clearly referring to the standard. – bolov Aug 28 '21 at 03:50
  • @bolov It's very heavily implied, but it's technically lacking "in standard C++" in crucial sentences and has a misleading anecdote about a pre-standard compiler that draws away from the implication. I'm guessing the author just remembered a cool bug from long time ago, assumed that it was a standard violation, possibly misintrepreted the rules that "allow the value change" and mistakenly added it to their list of standard violations. – eerorika Aug 28 '21 at 03:58
  • most likely yes – bolov Aug 28 '21 at 04:01
  • "It is guaranteed to [not] do anything" -- there is no such guarantee. There is a list of things that it won't do. Changing the value of the pointer argument is not in that list. – Pete Becker Aug 28 '21 at 14:08
  • @PeteBecker the one thing it *is* guaranteed to do is not invoke undefined behavior. The only way to get undefined behavior by deleting a null pointer twice would be if that pointer value were changed to non-null by the first delete. While that technically might not be against the rules of the language, it would certainly violate normal expectations and I'd consider such a compiler buggy. – Mark Ransom Aug 28 '21 at 15:36
  • @MarkRansom -- that's what I said: changing the value of the pointer argument is not prohibited, just as the video says. Sure, folks probably wouldn't like that, but that's not what the question is about. – Pete Becker Aug 28 '21 at 16:53
4

According to cppreference on the delete expression:

delete expression

...

For the first (non-array) form, expression must be a pointer to an object type or a class type contextually implicitly convertible to such pointer, and its value must be either null or pointer to a non-array object created by a new-expression, or a pointer to a base subobject of a non-array object created by a new-expression.

...

If expression evaluates to a null pointer value, no destructors are called, and the deallocation function may or may not be called (it's unspecified), but the default deallocation functions are guaranteed to do nothing when passed a null pointer.

Deleting nullptr twice is not undefined behavior.

Nathan Pierson
  • 5,461
  • 1
  • 12
  • 30
  • Yeah that what I found exactly, but just confuse why did he state that in this talk. – Kidsunbo Aug 28 '21 at 03:05
  • 2
    @Kidsunbo • He stated that in his talk because he was talking about compilers in the 1980s for C++, which was 10+ years before C++ was standardized. – Eljay Aug 28 '21 at 03:31
  • @Eljay He did also say that "we always obey the standard ... ignored the standard and got later problems, common example is ... you can't delete [null] twice". Which is wrong in the implied context of standard C++. The anecdote about pre-standard compiler seems odd given the context. – eerorika Aug 28 '21 at 03:43
  • Yeah, his reference to a pre-standard 1980s compiler where `delete p;` scrambled `p` is non-standard since at the time there was no standard. (Other than the *de facto* "standard" of 1985 C++PL (1e), and 1990 ARM & 1991 C++PL (2e). Which may not have been clear of the expected `delete p;` behavior.) Maybe `Foo* p = nullptr; delete p; delete p;` is **undefined behavior** on the second delete that accesses the (now) not allowed to be accessed `p`, in which case *today I learned...* and *oh myyy!* q.v. https://stackoverflow.com/a/5002201/4641116 (thx Peter) – Eljay Aug 28 '21 at 12:33
0

The standard does not say anywhere that delete x; does not change the value of x. That's the point that Dewhurst is making.

Yes, compilers these days don't change the value of x, but that doesn't mean that they are not allowed to. He's absolutely right that after

int *ip = NULL;
delete ip;

there is no requirement that ip is still a null pointer.

We typically say that deleting a null pointer has no effect, but that's a bit of a simplification. The wording in the standard for deleting null pointers is phrased negatively: "if [the pointer value] is not a null pointer, ...". So there are things that the standard implicitly says won't be done. But those things don't include changing the original pointer value.

And, turning it around,

int *ip = new int;
delete ip;
delete ip;

that second delete could be okay, if the compiler sets ip to NULL as part of the first delete. Of course, while that's allowed, it's not required, so don't rely on that. <g>

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Are implementations really permitted to assign to the operand of `delete` when it just happens to be interpretable as a non-const lvalue? I don't think the standard explicitly says that `new T[n]` doesn't modify `n`, but the lack of any suggestion that it can should be enough to guarantee that. Vendors can't just add arbitrary side effects to the behavior specified in the standard. – benrg Sep 25 '21 at 00:05