Можно ли использовать volatile везде, где используется const? - PullRequest
4 голосов
/ 21 января 2012

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

volatile dummy_class
volatile dummy_class&
dummy_class volatile*
dummy_class *volatile
dummy_class volatile *volatile

Все это разные случаи, когда задействован const, использовать одну и ту же семантикуподать заявку на volatile?

Ответы [ 4 ]

6 голосов
/ 21 января 2012

Почти.Оба являются cv-qualifiers и могут использоваться практически везде, где могут другие.Единственное место, где они появляются в грамматике C ++, находится здесь:

cv-qualifier:constvolatile

А остальная часть грамматики ссылается на них как cv-qualifier .

Обратите внимание, что в одном месте вы не упомянули, где cv-qualifiers можно использовать:

struct X {
    void f() const;
    void g() volatile;
    void h() const volatile;
};

См. http://drdobbs.com/cpp/184403766 для использования более поздней версии.

Однако, естьправило, которое вы не можете объединить const и mutable как в:

stuct X {
    mutable const int x; // error
    mutable volatile int y; // valid
};

Соответствующее место в стандарте - [dcl.stc]:

Спецификатор mutable может применяться только к именам членов данных класса (9.2) и не может применяться к именам, объявленным как const или static [...]

2 голосов
/ 21 января 2012

Это раздел 3.9.3 CV-квалификаторы из C ++ 11 черновик n3290:

Тип, упомянутый в 3.9.1 и 3.9.2, является cv-неквалифицированным типом. Каждый тип , который является резюме без квалификации или неполный тип объекта или void (3.9) имеет три соответствующие cv-квалифицированные версии своего типа : a версия с квалификацией const, версия с квалификацией volatile и версия с квалификацией const. Термин объект Тип (1.8) включает в себя cv-квалификаторы, указанные при создании объекта. Наличие константного спецификатора в decl-specier-seq объявляет объект с константным типом объекта; такой объект называется объектом const. Присутствие volatile-спецификатора в decl-specier-seq объявляет объект типа volatile-квалифицированного объекта; такой объект называется летучим объектом. Присутствие обоих cv-квалификаторов в decl-specier-seq объявляет объект типа const-volatile-квалифицированного объекта; такой объект называется постоянным летучим объектом. CV-квалифицированный или cv-неквалифицированные версии типа являются различными типами; однако они должны иметь одинаковое представление и требования к выравниванию (3.9) .51

Так что const и volatile можно использовать в одних и тех же местах, возможно, в сочетании.

В пункте 3 этого раздела отмечается небольшая разница в том, как они применяются к объектам класса:

Каждый нестатический, не изменяемый , не ссылочный элемент данных объекта класса с константной квалификацией является константным fied, каждый нестатический, не эталонный элемент данных объекта класса с изменяемой квалификацией является с квалификацией и аналогично для членов класса const-volatile. См. 8.3.5 и 9.3.2 относительно типов функций, которые имеют CV-классификаторы.

но это довольно логично.

volatile -квалифицированные объекты имеют более строгие требования к правилу как если бы , а именно:

Доступ к летучим объектам оценивается строго по правилам абстрактной машины.

Волатильность привязывается к объекту таким же образом, const делает:

dummy_class volatile* // non-volatile pointer to volatile object
dummy_class *volatile // volatile pointer to non-volatile object
dummy_class volatile *volatile // volatile pointer to volatile object

Для нестатических функций-членов (§9.3.1):

Нестатическая функция-член может быть объявлена ​​как const, volatile или const volatile. Эти cv-квалификаторы влияет на тип указателя this (9.3.2). Они также влияют на тип функции (8.3.5) функции-члена; функция-член, объявленная const, является функцией-членом const, функция-член, объявленная как volatile, функция volatile и функция-член, объявленная как const volatile, является постоянным членом функция.

Таким образом, волатильность, подобная константности, применяется к типу this внутри функции.

Ни const, ни volatile не могут быть применены к статическим функциям-членам.

1 голос
/ 21 января 2012

В C ++ 2003 я думаю, что вы не можете определить static int volatile член класса, в то время как вы можете сделать это с static int const членом: последний становится константным выражением и до тех пор, пока вам не нужен адрес или ссылку на объект, у вас все будет в порядке. Для C ++ 2011 я не знаю, изменилось ли это, потому что вы можете инициализировать члены в определении класса, и я не знаю, распространяется ли это на статические члены.

1 голос
/ 21 января 2012

Любая переменная может быть объявлена ​​const или volatile (или обеими), но они имеют различную семантику.

Ключевое слово const указывает, что переменная является константой. Ключевое слово volatile указывает, что содержимое переменной может изменяться, даже если вы ничего не назначаете ей.

Например, если у вас есть этот кусок кода

int a = ...;
int b = ...;
int sum1 = (a + b) * 2;
int sum2 = (a + b) + 16;

и включить оптимизацию на вашем компиляторе, компилятор может оптимизировать предыдущий код в следующее:

int a = ...;
int b = ...;
int temp = a + b;
int sum1 = temp * 2;
int sum2 = temp + 16;

Эта оптимизация происходит потому, что компилятор предполагает, что значения a и b не изменятся при вычислении sum1 и sum2, поэтому a + b не изменится. Если вы объявите a или b как volatile, это предположение будет отменено, что означает, что компилятор будет генерировать код, который вычисляет a + b каждый раз, а не сохранять его во временном местоположении. Это потому, что объявление a или b volatile указывает на то, что a или b (и, следовательно, a + b) могли измениться между выполнением двух операторов.

Хотя volatile выглядит как бесполезное ключевое слово, оно используется в многопоточных приложениях и при выполнении операций ввода-вывода с отображением в памяти (то есть при использовании системной памяти для связи с оборудованием). Например, в GameBoy Advance необходимо прочитать определенную область памяти, чтобы определить, какие клавиши нажимаются одновременно. Если вы объявите указатель на эту конкретную ячейку памяти как энергозависимый, всегда будет гарантировано, что вы будете каждый раз читать эти конкретные данные из памяти.

...