Изменение постоянной стоимости

Предположим, у меня есть определение структуры:

struct thing
{
    thing* x;
    int z;

    thing() : x(this), z(0) {}
    void foo() const
    {
        this->x->z++;
    }
};

Обратите внимание, что я создаю изменяемый указатель на себя (злой смех)

И тогда я могу использовать это позже следующим образом:

int main()
{
    const thing c;
    c.foo();
    assert(c.z == 1);
    c.foo();
    assert(c.z == 2);
    return c.z;
}

И, как вы видите, кажется, что я могу изменить постоянную ценность... это UB?

Ответ 1

[Dcl.type.cv] р4:

За исключением того, что любой член класса, объявленный mutable ([dcl.stc]), может быть изменен, любая попытка изменить ([expr.ass], [expr.post.incr], [expr.pre.incr]) объект const ([ basic.type.qualifier]) в течение своего жизненного цикла ([basic.life]) приводит к неопределенному поведению.

[Basic.type.qualifier] p1:

Объектом const является объект типа const T или не изменяемый подобъект такого объекта.

cz - объект const, потому что он является не изменяемым подобъектом c. Ваш код пытается изменить его в течение своей жизни. Из этого следует, что код имеет неопределенное поведение.

Ответ 2

foo -function само по себе было бы хорошо, так как const функции - члены, такие как T::foo() const просто указать, что this имеет тип const *T; То, что a (не const) член указывает на один и тот же объект, не имеет значения.

Однако объект c на первом месте объявляется как const. Таким образом, UB изменяет содержимое c на любой код, включая функцию (per se correct) member foo.