изменчивый и изменчивый в C ++

85

У меня вопрос о разнице между изменчивым и изменчивым. Я заметил, что оба значения означают, что это можно изменить. Что еще? Это одно и то же? Какая разница? Где они применимы? Почему предлагаются две идеи? Как их использовать по-другому?

Большое спасибо.

дверь в небо
источник

Ответы:

112

mutableПоле может быть изменено даже в объекте , доступном через constуказатель или ссылки, или в constобъекте, так что компилятор знает , чтобы не прятать его в памяти R / O. volatileРасположение один , который может быть изменен с помощью кода компилятор не знает о (например , каком - то драйвере уровня ядра), так что компилятор не знает , чтобы оптимизировать , например , зарегистрировать присвоение этого значения при недопустимом предположении , что значение «не может иметь изменено "с момента последней загрузки в этот регистр. Очень разная информация передается компилятору, чтобы остановить самые разные недопустимые оптимизации.

Алекс Мартелли
источник
13
volatileобъекты также могут быть изменены процессами, вообще не задействующими ЦП. Например, регистр приема байтов в коммуникационном периферийном устройстве может увеличиваться на единицу при получении байта (и это может даже вызвать прерывание). Другой пример - регистр флагов ожидающих прерываний в периферийном устройстве.
Mike DeSimone
55
Кроме того, volatileэто не только означает, что объект может изменяться вне зависимости от компилятора - это также означает, что записи в объект не могут быть устранены компилятором, даже если эти записи кажутся бесполезными. Например: x = 1; x = 0; если xявляется изменчивым, компилятор должен выполнить обе операции записи (что может иметь значение на аппаратном уровне). Однако для энергонезависимого объекта компилятор может не беспокоиться о написании, 1поскольку он никогда не использовался.
Майкл Берр,
15
Объект может быть отмечен как, так constи volatile! Поменять предмет нельзя, но можно поменять за спиной.
CTMacUser
2
@Destructor: обычная ситуация для записи в регистр аппаратного устройства.
Майкл Берр
5
@Destructor, допустим, вы контролируете состояние светодиода. Запись 0 выключает его, запись 1 включает. Если мне нужно мигать светодиодом, чтобы сообщить о каком-либо статусе ошибки, но компилятор решает оптимизировать все записи, кроме последней, поскольку ни одно из значений не используется, тогда светодиод никогда не мигает, и желаемое поведение не реализуется .
iheanyi
28

mutable: Ключевое слово mutable переопределяет любой включающий оператор const. Изменяемый член константного объекта может быть изменен.

volatile: Ключевое слово volatile - это модификатор, зависящий от реализации, используемый при объявлении переменных, который не позволяет компилятору оптимизировать эти переменные. Volatile следует использовать с переменными, значение которых может изменяться неожиданным образом (например, из-за прерывания), что может конфликтовать с оптимизацией, которую может выполнить компилятор.

Источник

Сиань
источник
Вы сказали, что Volatile should be used with variables whose value can change in unexpected waysлучше использовать его в случайном порядке?
Асиф Муштак
@AsifMushtaq не ценности. способами. mutable влияет на разрешения написанного вами кода. Таким образом, вы можете получить доступ к переменной через ссылку const ptr или const. Что, если это не ваш код меняет его? Что-то компилятор не может проверить ptr или ссылочный тип? Это непостоянно. Кроме того, volatile заставляет кэш записывать обратно в основную память. Таким образом, это используется МНОГО с многопоточным кодом. :)
Дэн
22

Это определенно НЕ одно и то же. Mutable взаимодействует с const. Если у вас есть константный указатель, вы обычно не можете изменять члены. Mutable представляет собой исключение из этого правила.

Volatile, с другой стороны, совершенно не связано с изменениями, внесенными программой. Это означает, что память может измениться по причинам, не зависящим от компилятора, поэтому компилятор должен каждый раз читать или записывать адрес памяти и не может кэшировать содержимое в регистре.

Бен Фойгт
источник
«Volatile, с другой стороны, совершенно не связан с изменениями, сделанными программой ...» - хммм, сделайте член volatile и посмотрите, что ломается во время компиляции. Попытка добавить volatile постфактум очень похожа на попытку добавить const постфактум ... Мучительно.
jww
@jww: Это совершенно не связано с записями, сделанными программой. Вы можете взять адрес объекта типа T, сохранить его в const T*и прочитать из него. Если вы создадите этот объект volatile, сохранить его адрес в нем const T*не удастся, даже если вы никогда не пытаетесь писать. volatileа изменения / модификации / записи в память из программного кода полностью ортогональны.
Бен Фойгт
17

Грубый, но эффективный способ осмыслить разницу:

  • Компилятор знает, когда изменяемый объект изменяется.
  • Компилятор не может знать, когда изменяется изменчивый объект.
Джонатан Леффлер
источник
1
В этом ключе: volatilebytes_received, mutablereference_count.
Mike DeSimone
11

Отмеченная переменная mutableпозволяет изменять ее в объявленном методе const.

Отмеченная переменная volatileсообщает компилятору, что он должен читать / записывать переменную каждый раз, когда ваш код также сообщает об этом (т.е. он не может оптимизировать доступ к переменной).

Кайл Латс
источник
4

Я хотел бы добавить, что volatile также очень полезен при работе с многопоточными приложениями, т.е. у вас есть основной поток (где живет main ()), и вы создаете рабочий поток, который будет продолжать вращаться, пока переменная app_running имеет значение true. main () контролирует, является ли app_running истинным или ложным, поэтому, если вы не добавите атрибут volatile к объявлению app_running, если компилятор оптимизирует доступ к app_running в коде, выполняемом вторичным потоком, main ( ) может изменить "app_running" на false, но вторичный поток продолжит работу, потому что значение было кэшировано. Я видел такое же поведение при использовании gcc в Linux и VisualC ++. Атрибут "volatile", помещенный в объявление "app_running", решил проблему. Так,

BinCoder
источник
1
Нет! Это распространенное заблуждение. C ++ 11 и C11 представили атомики для этой цели stackoverflow.com/questions/8819095/…
KristianR