Предположим, у меня есть определение структуры:
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?
Нет общего правила, которое гласит, что вы не можете ниспровергнуть const без приведения.





Сама функция foo будет в порядке, поскольку функции-члены const, такие как T::foo() const, просто указывают, что this относится к типу const *T; Тот факт, что член (неконстантный) указывает на один и тот же объект, тогда не имеет значения.
Однако объект c в первую очередь объявлен как const. Таким образом, UB - изменять содержимое c с помощью любого кода, включая (как таковую правильную) функцию-член foo.
А как насчет того, что c - это const?
@ Натан Оливер: да; вы не можете изменять значение c->x, но можете изменить объект, на который ссылается c->x; поэтому c->x->z++ действителен, даже если c является константой.
Но поскольку c->x->z++ - это c.z++, разве это не UB?
Я думаю, что в C++ 11 это нарушение константы. До C++ 11, вероятно, это просто плохой агент.
@NathanOliver: Нет, я совершенно уверен, что это не UB. const не означает, что объект в целом неизменяем; он просто заявляет, что его нельзя изменять с помощью указателя (const) под рукой. Таким образом, вы не можете изменить z через (const*) this->z++, а через другой путь к этому объекту, то есть через this->x->z++.
Ваш пример действителен только потому, что value изначально не был объявлен как const ... но его экземпляр thing объявлен как const ... и если вы попытаетесь использовать const_cast<thing*>(this)->z++;, это будет неопределенное поведение .. Итак, почему он может изменить его через мелкая копия this .. * Примечание :( Я не голосовал против.
@Brandon: Ш ... Да, ты прав. Я придерживался самой функции foo, но проигнорировал тот факт, что OPs c изначально является константой.
[dcl.type.cv] p4:
Except that any class member declared
mutable([dcl.stc]) can be modified, any attempt to modify ([expr.ass], [expr.post.incr], [expr.pre.incr]) a const object ([basic.type.qualifier]) during its lifetime ([basic.life]) results in undefined behavior.
[basic.type.qualifier] p1:
A const object is an object of type
const Tor a non-mutable subobject of such an object.
c.z - это константный объект, потому что это неизменяемый подобъект c. Ваш код пытается изменить его в течение своего жизненного цикла. Отсюда следует, что код имеет неопределенное поведение.
Да, это UB, так как
c- const.