This question is different from:
Is a destructor considered a const function?
new-expression and delete-expression on const reference and const pointer
Deleting a pointer to const (T const*)
I wrote a class Test
like this.
class Test {
private:
int *p;
public:
//constructor
Test(int i) {
p = new int(i);
}
Test & operator = (const Test &rhs) {
delete p;
p = new int(*(rhs.p));
return *this;
}
};
When the parameter rhs
of the operator function is itself (i.e. Test t(3); t = t;
), delete p;
also changes the pointer p
of rhs
. Why is this allowed?
C++ standard (N3092, "3.7.4.2 Deallocation functions") says
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined.
(Note: delete-expression internally calls a deallocation function. So this excerpt is related with delete
operator.)
So I think delete p;
may change the member p
of rhs
though rhs
is a const reference.
Someone may insist that "to render a pointer invalid is not to change the value of a pointer" but I don't find such a statement in the standard. I doubt there is a possibility that the address pointed by rhs
's p
has been changed after delete p;
in operator =
(*).
(*): Whether or not this situation can be reproduced on popular compilers doesn't matter. I want a theoretical guarantee.
Supplement:
I've changed delete p;
to delete rhs.p;
, but it still works. Why?
Full code here:
#include <iostream>
class Test {
private:
int *p;
//print the address of a pointer
void print_address() const {
std::cout << "p: " << p << "\n";
}
public:
//constructor
Test(int i) {
p = new int(i);
}
Test & operator = (const Test &rhs) {
print_address(); //=> output1
delete rhs.p;
print_address(); //=> output2
p = new int(*(rhs.p));
return *this;
}
};
int main() {
Test t(3);
t = t;
}
In this case, it is guaranteed that p
is invalidated. But who guarantees invalidate != (change the value)
? i.e. Does the standard guarantee that output1
and output2
are the same?
So I think
delete p;
may change the memberp
ofrhs
thoughrhs
is a const reference.
No. delete p;
doesn't change p
. Invalidation is not modification.
Regardless, having a const reference to an object (rhs
) does not by any means prevent the referred object form being modified. It merely prevents modification through the const reference. In this case we access the object through this
which happens to be a pointer to non-const, so modification is allowed.
Someone may insist that "to render a pointer invalid is not to change the value of a pointer" but I don't find such a statement in the standard.
The behaviour of delete expression is specified in [expr.delete]. Nowhere in that section does it mention that the operand is modified.
Becoming invalid is specified like this:
[basic.compound]
... A pointer value becomes invalid when the storage it denotes reaches the end of its storage duration ...
Note that it is the value that becomes invalid. The pointer still has the same value because the pointer was not modified. The value that the pointer had and still has is simply a value that no longer points to an object - it is invalid.
Supplement: I've changed
delete p;
todelete rhs.p;
, but it still works. Why?
Answer 2. From previous question no longer applies, but answer 1. does. delete rhs.p;
does not modify rhs.p
.
Calling delete
on a member pointer frees the memory the pointer points to but does not change the pointer itself. Thus, it does not change the bitwise contents of the object, thus it can be done in a const
member.
C++ only cares about bitwise const (of the object the method is invoked on). Not logical const. If no bits in the object change, then all is well - const wise - as far as the C++ language is concerned. It does not matter whether the logical behaviour of the object is changed (for example by changing something member pointers point to). That's not what the compiler checks for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With