20

Inspired by this question.

Suppose in C++ code I have a valid pointer and properly delete it. According to C++ standard, the pointer will become invalid (3.7.3.2/4 - the deallocation function will render invalid all pointers referring to all parts of deallocated storage).

At least in most implementations it preserves the value and will store exactly the same address as before delete, however using the value is undefined behavior.

Does the standard guarantee that the pointer will preserve its value or is the value allowed to change?

18
  • 4
    Does the delete signature allow it to access the pointer, i.e. anything other than pass-by-value? Commented Feb 15, 2011 at 9:52
  • 2
    Interesting question, but purely academic curiosity, I hope. I can't imagine why you would need to know this when writing code. Commented Feb 15, 2011 at 9:54
  • 1
    @Cody Gray: You're right. Using the pointer (for example, trying to printf() it) after delete is UB, so the user couldn't even legally read the pointer and compare to the original value. Commented Feb 15, 2011 at 9:58
  • 2
    @Rup: Delete is, in this case, an operator without a signature. ("Operator delete" is the function which is called by the delete operator or explicitly called.) Commented Feb 15, 2011 at 10:00
  • 2
    @FredNurk: It might be clearer to say that it's a keyword that invokes an operator (operator delete) to delegate its work. And that the keyword has no 'signature'. Commented Feb 15, 2011 at 10:02

7 Answers 7

23

No, it's not guaranteed and an implementation may legitimately assign zero to an lvalue operand to delete.

Bjarne Stroustrup had hoped that implementations would choose to do this, but not many do.

http://www.stroustrup.com/bs_faq2.html#delete-zero

Sign up to request clarification or add additional context in comments.

4 Comments

Can it assign any other address except zero?
it's pretty much useless since all the copies of the pointer would be unchanged...
@MatthieuM.: I don't say that I agree with Bjarne on this point. stackoverflow.com/questions/1265666/…
@sharptooth: Yes, it could do (almost) anything.
15

If, for whatever reason, you want to be sure the pointer variable is not changed by delete, write:

delete p + 0;

1 Comment

interesting way, I would have said delete a copy of the pointer but yeah that would work too.
3

I believe that most implementations will keep the value, only for the sake of having no reason to change it. But regardless of whether the value is kept, it's still a useless pointer, is it not?

1 Comment

Yes, it's useless either way. But the nature of the bugs you'd encounter if you tried to use it anyway would be completely different.
1

Consider, how would you check or rely on any "yes" or "no" answer? You can't. Or, you can, but the result of that checking (except for nullpointer) is Undefined Behavior.

You can't check a non-null value after a delete, so the question is in general meaningless.

Also, the argument to delete can be an rvalue expression, so the question is meaningless.

Cheers & hth.,

6 Comments

Surely you can check by looking at the values of the bytes in memory before, remembering them, and looking again afterwards. It's true that those bytes might be a pointer value representation before and (say) a trap representations after, so in a sense there's no "after value" about which we can ask, "has it changed?". But it's meaningful to ask about the output of e.g. char *x = 0; char one = *(char*)(&x); delete x; char two = *(char*)(&x); std::cout << (one == two);. If it outputs false I think it's fair to say that something about x has changed, if not precisely the pointer value.
(Actually, I think I need char *x = new char; there, since null pointers are a special case). Also, the fact that the argument to delete can be an rvalue has no direct bearing on what happens when it's an lvalue. Of course, it might suggest to implementers that doing different things in the two cases would be unnecessary effort.
@Steve: it's usually no good to serialize pointer values (e.g. storing them in files), but one might conceivably have a pointer value in a POD struct and compare it bitwise with earlier copy. i think that that is pretty marginal case. so, in general, meaningless.
"In general" meaning, "except in the cases where it is meaningful in the sense that it affects the behaviour of a strictly conforming program"? Granted, not a strictly conforming program that you or I have any motivation to write. To be honest, I think your hope that your answer will help is forlorn ;-)
@PravasiMeet: The simplest realistic example is probably delete foo(), where foo is a function that serves up the pointer value. Bjarne Stroustrup, the language creator, also provides some examples in his FAQ item about this.
|
1

A pointer is not guaranteed to be of any meaningful value in of itself other than the range in which it was allocated and one past the end of that range.

What you might be questioning is whether, say, you were doing your own leak checking so you wrote function to remove a pointer from a map after you had done a delete. That would use std::less which is guaranteed to work with pointers that do not point within a range, and would presumably work too with pointers that pointed to memory that is no longer valid.

Of course you might get your garbage collecting to do the "remove" just before deleting the memory it was pointing to.

As it is with the standard, if the value you pass to delete is not an l-value it is guaranteed to maintain the same value, but if it is an l-value it is implementation defined.

Comments

1

This question is important!

I have seen that Visual Studio 2017 has changed a pointer's value after delete. It caused a problem because I was using a memory tracing tool that collected pointers after each operator new and was checking them after delete. Pseudo code:

Data* New(const size_t count)
{
    Data* const ptr(new Data[count]);
    #ifdef TEST_MODE
    DebugMemory.Collect(ptr);
    #endif
    return ptr;
}

void Delete(Data* const ptr)
{
    delete[] ptr;
    #ifdef TEST_MODE
    DebugMemory.Test(ptr);
    #endif
}

This code worked good in Visual Studio 2008, but was failing in Visual Studio 2017, so I have changed the order of operations in the second function.

However, the question is good, and the problem exists. Experienced engineers should be aware of that.

Comments

0

The signature of the global operator delete, as required by the standard 3.7.3.2/2:

Each deallocation function shall return void and its first parameter shall be void*.

This means that delete cannot modify the pointer you pass to it, and it will always retain its value.

1 Comment

The function "operator delete" is not the delete operator. The signature of that function has nothing to do with whether the operator can modify a value. (That function cannot itself modify any value, of course. It can't even take the pointer by reference or a pointer to the pointer, as it doesn't have the type information from the original pointer.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.