Постоянное изменение значения

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

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?

Да, это UB, так как c - const.

geza 08.10.2018 23:44

Нет общего правила, которое гласит, что вы не можете ниспровергнуть const без приведения.

curiousguy 21.10.2018 22:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
2
322
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Однако объект c в первую очередь объявлен как const. Таким образом, UB - изменять содержимое c с помощью любого кода, включая (как таковую правильную) функцию-член foo.

А как насчет того, что c - это const?

NathanOliver 08.10.2018 23:23

@ Натан Оливер: да; вы не можете изменять значение c->x, но можете изменить объект, на который ссылается c->x; поэтому c->x->z++ действителен, даже если c является константой.

Stephan Lechner 08.10.2018 23:26

Но поскольку c->x->z++ - это c.z++, разве это не UB?

NathanOliver 08.10.2018 23:27

Я думаю, что в C++ 11 это нарушение константы. До C++ 11, вероятно, это просто плохой агент.

Eljay 08.10.2018 23:28

@NathanOliver: Нет, я совершенно уверен, что это не UB. const не означает, что объект в целом неизменяем; он просто заявляет, что его нельзя изменять с помощью указателя (const) под рукой. Таким образом, вы не можете изменить z через (const*) this->z++, а через другой путь к этому объекту, то есть через this->x->z++.

Stephan Lechner 08.10.2018 23:29

Ваш пример действителен только потому, что value изначально не был объявлен как const ... но его экземпляр thing объявлен как const ... и если вы попытаетесь использовать const_cast<thing*>(this)->z++;, это будет неопределенное поведение .. Итак, почему он может изменить его через мелкая копия this .. * Примечание :( Я не голосовал против.

Brandon 08.10.2018 23:39

@Brandon: Ш ... Да, ты прав. Я придерживался самой функции foo, но проигнорировал тот факт, что OPs c изначально является константой.

Stephan Lechner 08.10.2018 23:42
Ответ принят как подходящий

[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 T or a non-mutable subobject of such an object.

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

Другие вопросы по теме