Вы, вероятно, знакомы с const
методами и правильностью const (см. "Пункт 15 - Использование const проактивно" в C ++ Стандарты кодирования Саттера и Александреску),и volatile
работает аналогичным, но немного отличающимся образом, чтобы дать то, что можно было бы назвать «изменчивой корректностью».
Как и const
, volatile
является модификатором типа.При присоединении к функции-члену, как в вашем примере, либо модификатор (или оба!) Означают, что объект, для которого вызывается метод, должен иметь или быть преобразованным к этому типу.
Учтите:
struct A
{
void f();
void cf() const;
void vf() volatile;
void cvf() const volatile;
// ...
};
void foo( A& a, const A& ca, volatile A& va, const volatile A& cva )
{
a.f(); // Ok
a.cf(); // Ok: Can convert non-const obj to const obj
a.vf(); // Ok: Can convert non-volatile obj to volatile obj
a.cvf(); // Ok: Can convert non-cv obj to cv obj
ca.f(); // Error: can't call non-const method on const obj
ca.cf(); // Ok
ca.vf(); // Error: can't call non-const method on const obj
ca.cvf(); // Ok: Can convert
va.f(); // Error: can't call non-volatile method on volatile obj
va.cf(); // Error: can't call non-volatile method on volatile obj
va.vf(); // Ok
va.cvf(); // Ok: Can convert
cva.f(); // Error: can't call non-cv method on cv obj
cva.cf(); // Error: can't call non-cv method on cv obj
cva.vf(); // Error: can't call non-cv method on cv obj
cva.cvf(); // Ok
}
Обратите внимание, что это ошибки во время компиляции, а не ошибки во время выполнения, и именно здесь возникает его потенциальная полезность.
Const -корректность предотвращает непреднамеренные ошибки во время компиляции а также делает код «проще для понимания, отслеживания и анализа» (Саттер и Александреску).Volatile-корректность может функционировать аналогично, но используется гораздо реже (обратите внимание, что const_cast
в C ++ может отбрасывать const
, volatile
или const volatile
, но вместо того, чтобы называть его cv_cast
или подобным, он назван в честь const
, потому что он гораздо чаще используется для отбрасывания всего лишь const
).
Например, в "volatile - лучший друг многопоточного программиста" , Андрей Александреску приводит несколько примеровкак это можно использовать, чтобы компилятор автоматически определял условия гонки в многопоточном коде.В нем также есть много объяснений о том, как работают модификаторы типов, но см. Также его последующие комментарии в его последующем столбце .
Обновление :
Обратите внимание, что C ++ 11 меняет значение const
. Так говорит Саттер : «const
теперь действительно означает« только для чтения »или« безопасно читать одновременно »- либо физически / побитово const
, либо внутренне синхронизировано, так что любые фактические записи синхронизируютсяс любым возможным одновременным доступом const
, чтобы вызывающие абоненты не могли заметить разницу. "
В другом месте он отмечает , что, хотя C ++ 11 добавил примитивы параллелизма, volatile
все еще не один из них: «Изменчивые переменные C ++ (которые не имеют аналогов в таких языках, как C # и Java) всегда выходят за рамки этой и любой другой статьи о модели памяти и синхронизации. Это потому, что переменные C ++ не относятся к потокамили общение вообще и не взаимодействовать с этими вещами. Скорее, энергозависимую переменную C ++ следует рассматривать как портал в другую вселенную за пределами языка - область памяти, которая по определению не подчиняется модели памяти языка, поскольку эта область памятидоступ к аппаратным средствам (например, записанный на дауghter card), имеют более одного адреса или являются «странными» иными словами.Таким образом, изменчивые переменные C ++ являются универсальным исключением из любого руководства по синхронизации, потому что они всегда неотъемлемы и являются «нестабильными» и несинхронизируемыми с использованием обычных инструментов (мьютексов, атомик и т. Д.) И, в более общем смысле, существуют вне всех нормалей языка и компилятора, включая то, что они обычноне может быть оптимизирован компилятором .... Подробнее см. мою статью ' volatile против volatile .' "