Why compilers do not assign NULL to pointer variable automatically after deleting dynamic allocated memory? [duplicate]
Asked Answered
N

4

0

I have small piece of code:

#include <iostream>
using namespace std;

int main() 
{
    int *p = new int(10);

    if(p != NULL)
    {
        cout<<"Deleted dynamic allocated memory"<<endl;
        delete p;
    }

    if(p == NULL)
    {
        cout<<"NULL"<<endl;
    }
    else
    {
        cout<<"Not NULL"<<endl;
    }
    return 0;
}

After deleting dynamic allocated memory using delete operator, Why compilers do not assigned NULL to pointer(like p = NULL) automatically?

Nomism answered 17/7, 2017 at 11:19 Comment(3)
For the same reason a member function isn't dynamically dispatched unless explicitly request it to be. C++ doesn't make you pay for what you don't use.Kellsie
You can delete something, which is not an lvalue. For example, delete p+1. In this case, you cannot set anything to nullptr.Adela
imho it is good that compilers dont do it. To my experience most confusion about pointers for beginners is due to thinking there would be some magic link between a pointer and the pointee and making delete p set p to 0 just feeds this misunderstanding.Obstreperous
O
9
  1. It would often be unnecessary, particularly in well-written code.

  2. It could hide away bugs.

  3. delete p; would be syntactically idiosyncratic if it modified its argument.

On (1) it would be particularly wasteful with std::unique_ptr.

In other words, burdening the programmer with this job if necessary is the right thing to do.

Odonnell answered 17/7, 2017 at 11:23 Comment(20)
on 3) afaik delete p is allowed to set p to 0. And I remember Soustroup saying somewhere that he wished that it was mandatory (however I disagree with him on that point)Obstreperous
@tobi303: You are indeed correct. I'm glad Stroustrup did not get his way on this.Odonnell
@tobi303 - What Bathsheba said. The looser contract of a mere "indeterminate value" makes for better machine code.Kellsie
@StoryTeller I get the point, I was just a bit confused because 3) reads like delete does not modify its argument, but in fact it is allowed to do soObstreperous
@tobi303 - I think what point (3) means is that the syntax for delete doesn't suggest p could be modified.Kellsie
@StoryTeller but delete is allowed to modify p. Nevermind, I think in fact we agree on the point and its just about the wording...Obstreperous
@tobi303 - Just one last thing. You know delete can modify p, and I know that. Anybody who's read the standard or worked enough with C++ knows that. But from a pure syntax perspective, I don't think it's obvious.Kellsie
@StoryTeller finally I got it. Thanks for your patience ;)Obstreperous
@StoryTeller: "You know delete can modify p". Where is this written in the standard? I cannot find it.Adela
@Adela - new.delete.single for instance. Note the ptr is "invalid" afterwards. Which means a conforming C++ compiler can still modify it however it likes after delete was successfully executed.Kellsie
@StoryTeller: Hmm. void operator delete(void* ptr) noexcept; If I wanted to be picky, ptr is a local variable here. So definitely doesn't modify my original variable. What if my expression for delete is not an lvalue?Adela
@Adela - The value itself (address if you will) becomes invalid (there are several links to follow about invalid pointer values). An implementation knowing the value is now invalid may do whatever with the pointer itself.Kellsie
@StoryTeller: yes, ok, but where is this written in the standard? new.delete.single refers to ptr, which is not the variable at delete XXX. I've read all the available material here in SO, but haven't found an answer. It is not a common knowledge, I think. Even in this answer: "delete p; would be syntactically idiosyncratic if it modified its argument.". This doesn't mean to me that delete is allowed to modify its argument.Adela
@Adela - (shrug) Then you'll have to read more. The value is invalid, even comparing the pointer to nullptr is not allowed without UB. If you can't expect any observable behavior, it automatically means great leeway for the implementation.Kellsie
"The value is invalid, even comparing the pointer to nullptr is not allowed without UB" is very, very important if you like to write truly portable code.Odonnell
@StoryTeller: what do you think, even memcpy(buffer, &ptr, sizeof(ptr)); is disallowed? Or directing a const char *a to &ptr, and reading from a?Adela
@Adela - I don't have to think. It's completely up to the implementation. I was wrong in one thing, which was thinking it's all UB. An implementation is in fact obligated to document what it does. But if you read the footnote, what you suggested could cause a run-time error.Kellsie
@StoryTeller: yes, but this time I don't copy the pointer as a pointer, but as a memory-blob. So, does this mean, that I cannot memcpy a variable? Or, if I have a struct, which happen to have a pointer which has invalid value, then I cannot copy this struct? Does that mean that I cannot observe an invalid pointer value with a char *? It doesn't sound too good. Thanks for the patience, btw :)Adela
@Adela - Remember the leeway the implementation has? Assume the character types have trap values. Then nothing is stopping the implementation from overwriting ptr with those. And you'll get traps for a memory-blob as well. Don't think of it as a bad thing. If you have an invalid pointer value running around in your program, that's usually indicative of a bug.Kellsie
@StoryTeller: I've asked this as a question: #45150256Adela
P
2

Because it is extra work (= more clock cycles, less performance), that is usually not needed.

Pipkin answered 17/7, 2017 at 11:20 Comment(1)
And if you do need it, the cost in LOC is negligible.Kellsie
M
2

If your design calls for NULLing a pointer to indicate that it no longer points at something useful, you can add code to do that. But that should not be the default, because it can be insufficient and pointless.

NULL pointers don't solve every possible problem:

int *ip = new int;
int *ip1 = ip;
delete ip;
if (ip1)
    *ip1 = 3; // BOOM!

And they are often pointless:

struct s {
    int *ip;
    s() : ip(new int) {}
    ~s() { delete ip; } // nobody cares if ip is NULL, 'cause you can't see it
};
Marianelamariani answered 17/7, 2017 at 11:27 Comment(0)
O
0

They are allowed to do so, but it isnt mandatory. I think the reason they dont do it consitently is because anyhow you cant rely on it. For example consider this:

int* a = new int(3);
int* b = a;
delete a;
/// ....
if (b != 0) {              /// assume b is either null or points to something valid
     std::cout << *b;      /// ups 
}
Obstreperous answered 17/7, 2017 at 11:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.