Why can delete operator be used in const context?

mat*_*atn 6 c++ language-lawyer

This question is different from:


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;
        }

};
Run Code Online (Sandbox Code Playgroud)

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;

}
Run Code Online (Sandbox Code Playgroud)

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?

eer*_*ika 6

因此,我认为delete p;可能会改变成员prhs虽然rhs是一个常量引用。

  1. delete p;不会改变p。无效不是修改。

  2. 无论如何,对对象(rhs)进行const引用都不会阻止所引用的对象形式被修改。它只是防止通过const引用进行修改。在这种情况下,我们访问this恰好是指向非const指针的对象,因此允许进行修改。

有人可能会坚持认为“使指针无效并不意味着更改指针的值”,但我在标准中找不到这样的声明。

删除表达式的行为在[expr.delete]中指定。在该部分中没有任何地方提到修改操作数。

指定为无效是这样的:

[基本化合物]

...当指针表示的存储达到其存储持续时间的结尾时,该指针值将变为无效...

请注意,它是无效的。指针仍具有相同的值,因为未修改指针。指针拥有并仍然具有的值只是一个不再指向对象的值-它是无效的。


补充:我已更改delete p;delete rhs.p;,但仍然可以使用。为什么?

答案2。上一个问题不再适用,但答案1确实适用。delete rhs.p;不会修改rhs.p