Is the pointer guaranteed to preserve its value after `delete` in C++?
Asked Answered
B

7

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?

Bellaude answered 15/2, 2011 at 9:49 Comment(18)
Does the delete signature allow it to access the pointer, i.e. anything other than pass-by-value?Mezuzah
Interesting question, but purely academic curiosity, I hope. I can't imagine why you would need to know this when writing code.Kay
@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.Bellaude
@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.)Stovepipe
I am not able to understand the question. Can you provide some example?Maurili
@Harish: Something like this: I delete a pointer and it stores 0xDEADBEEF address after that.Bellaude
@Cody Gray: That depends - the information that a pointer holds it two-fold: (1) its actual address and (2) where it points. Sometimes the first one can be important - perhaps it should not - but could. Interesting question.Damson
@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'.Parch
Although not relevant in practice, this is an interesting question, BTW!Parch
@Bellaude Stores the address where?Maurili
@Harish: In the pointer that was the operand of delete.Bellaude
@Fred @Tomalak: The most correct way of referring to it is as a delete-expression. It's an expression; not an operator, function, delegated function, etc. (It does though, of course, have side-effects, like possible calling operator delete and kin.)Becket
@sharptooth: I understand. Unique question. I am eager to know the answer myself.Maurili
@Cody Gray: it's not purely academic, at least in the sense that if the value is modified then a strictly conforming program can tell the difference. You can't access the pointer value as a pointer value, but you can validly compare the values of the bytes that it occupies, before and after.Fraase
@Steve Jessop: If I store the original value and then memcmp() it with the value after delete will it not be undefined behavior?Bellaude
@sharptooth: I don't think so. memcmp doesn't use the pointer value, as far as I read the standard. It's not undefined behaviour to memcmp 4 bytes that just so happen to invalid as a float value, so why should it be undefined to memcmp 4 bytes that just so happen to be invalid as a pointer value? Memory can always be examined as bytes provided that it's still allocated, it doesn't matter what it does or doesn't represent. Just don't use the pointer value. The result of the memcmp maybe unspecified or implementation-defined, though, whichever the standard says about delete on lvalues.Fraase
@Tomalak: Note that the delete operator destructs the object before it calls operator delete to release the memory.Turkestan
@GMan: Correct. / @FredOverflow: True, it doesn't delegate all of its work.Parch
L
22

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

Lenorelenox answered 15/2, 2011 at 10:4 Comment(4)
Can it assign any other address except zero?Bellaude
it's pretty much useless since all the copies of the pointer would be unchanged...Asserted
@MatthieuM.: I don't say that I agree with Bjarne on this point. #1266166Lenorelenox
@sharptooth: Yes, it could do (almost) anything.Lenorelenox
T
15

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

delete p + 0;
Turkestan answered 15/2, 2011 at 10:47 Comment(1)
interesting way, I would have said delete a copy of the pointer but yeah that would work too.Respondent
D
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?

Dietz answered 15/2, 2011 at 9:54 Comment(1)
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.Cobos
R
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.

Respondent answered 15/2, 2011 at 9:57 Comment(0)
C
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.,

Coleridge answered 15/2, 2011 at 10:12 Comment(6)
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.Fraase
(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.Fraase
@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.Coleridge
"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 ;-)Fraase
@Cheersandhth.-Alf: how can argument to delete can be an rvalue expression? Will you please give an example?Sharpfreeze
@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.Coleridge
P
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.

Plating answered 28/7, 2018 at 6:40 Comment(0)
S
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.

Subbasement answered 15/2, 2011 at 9:57 Comment(1)
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.)Stovepipe

© 2022 - 2024 — McMap. All rights reserved.