Пространства имён
Варианты
Действия

cv (const и volatile) квалификаторы типа

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений(до C++17*)
Спецификатор noexcept(C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype(C++11)
auto(C++11)
alignas(C++11)
const/volatile
constexpr(C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr(C++11)
Определяемые пользователем(C++11)
Утилиты
Атрибуты(C++11)
Types
Объявление typedef
Объявление псевдонима типа(C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
Специальные функции-элементы
Шаблоны
Разное
 
Обьявления
 

Появляются в любом спецификаторе типа, включая последовательность-спецификаторов-объявленияграмматики объявления, чтобы указать константность или волатильность объявляемого объекта или именуемого типа.

  • const - определяет, что тип является константой.
  • volatile - определяет, что тип является volatile.

Содержание

[править]Объяснение

Любой тип (возможно неполный), отличный от функционального типа или ссылочного типа это тип из группы из следующих четырёх отдельных, но связанных типов:

  • cv-неквалифицированная версия.
  • const-квалифицированная версия.
  • volatile-квалифицированная версия.
  • const-volatile-квалифицированная версия.

Эти четыре типа в одной группе имеют одинаковые требования к представлению и выравниванию.

Считается, что типы массивов имеют ту же cv-квалификацию, что и типы их элементов.

[править]Объекты const и volatile

При первом создании объекта используемые cv-квалификаторы (которые могут быть частью последовательности-спецификаторов-объявления или частью декларатора в объявлении или частью идентификатора-типа в выражении new) определяют константность или волатильность объекта следующим образом:

  • Константный объект это
  • объект, тип которого является константным, или
  • не mutable подобъект константного объекта.
Такой объект нельзя изменить: попытка сделать это напрямую является ошибкой времени компиляции, а попытка сделать это косвенно (например, путём изменения константного объекта через ссылку или указатель на неконстантный тип) приводит к неопределённому поведению.
  • volatile объект это
  • объект, тип которого является volatile-квалифицированным,
  • подобъект volatile объекта, или
  • подобъект mutable const-квалифицированного объекта.
Каждый доступ (операция чтения или записи, вызов функции-элемента и т.д.) осуществляемый через выражение glvalue volatile-квалифицированного типа, рассматривается как видимый побочный эффект для целей оптимизации (т.е., в пределах одного потока выполнения, volatile доступ не может быть оптимизирован или переупорядочен с другим видимым побочным эффектом, который упорядочен до упорядочен после volatile доступа. Это делает volatile объекты пригодными для связывания с обработчиком сигнала, но не с другим потоком выполнения, смотрите std::memory_order). Любая попытка получить доступ к volatile объекту через glvalue не volatile типа (например, через ссылку или указатель на не volatile тип) приводит к неопределённому поведению.
  • Объект const volatile это
  • объект, тип которого имеет const-volatile-квалификацию,
  • не mutable подобъект const volatile объекта,
  • константный подобъект volatile объекта или
  • не mutable volatile подобъект константного объекта.
Ведёт себя как константный объект и как volatile объект.

Каждый cv-квалификатор (const и volatile) может появляться не более одного раза в любой последовательности cv-квалификаторов. Например, constconst и volatileconstvolatile не являются допустимыми последовательностями cv-квалификаторов.

[править]Спецификатор mutable

  • mutable - разрешает модификацию элемента класса, объявленного mutable, даже если содержащий его объект объявлен константным (т.е. элемент класса является mutable).

Может появляться в объявлении нестатических элементов класса нессылочного неконстантного типа:

class X { mutable constint* p;// OK mutable int*const q;// некорректно mutable int& r;// некорректно};

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

class ThreadsafeCounter { mutable std::mutex m;// "Правило M&M": mutable и mutex идут вместеint data =0;public:int get()const{std::lock_guard<std::mutex> lk(m);return data;}   void inc(){std::lock_guard<std::mutex> lk(m);++data;}};

[править]Преобразования

Существует частичное упорядочивание cv-квалификаторов по возрастанию ограничений. О типе можно сказать более или менее cv-квалифицированный, чем:

  • неквалифицированный < const
  • неквалифицированный < volatile
  • неквалифицированный < constvolatile
  • const < constvolatile
  • volatile < constvolatile

Ссылки и указатели на cv-квалифицированные типы могут быть неявно преобразованы в ссылки и указатели на более cv-квалифицированные типы, смотрите квалификационные преобразования для получения подробной информации.

Чтобы преобразовать ссылку или указатель на cv-квалифицированный тип в ссылку или указатель на менее cv-квалифицированный тип, необходимо использовать const_cast.

[править]Ключевые слова

const, volatile, mutable

[править]Примечание

Квалификатор const, используемый при объявлении нелокальной не volatile не шаблонной(начиная с C++14)не inline(начиная с C++17) переменной, которая не объявлена как extern, даёт ей внутреннее связывание. Это отличается от C, где константные переменные области видимости файла имеют внешнее связывание.

Грамматика языка C++ рассматривает mutable как спецификатор-класса-хранения, а не квалификатор типа, но это не влияет на класс хранения или связывание.

Некоторые варианты использования volatile устарели:

(начиная с C++20)

[править]Пример

int main(){int n1 =0;// неконстантный объектconstint n2 =0;// константный объектintconst n3 =0;// константный объект (то же что и n2)volatileint n4 =0;// volatile объект   conststruct{int n1; mutable int n2;} x ={0, 0};// константный объект с mutable элементом   n1 =1;// ok, модифицируемый объект// n2 = 2; // ошибка: немодифицируемый объект n4 =3;// ok, рассматривается как побочный эффект// x.n1 = 4; // ошибка: элемент константного объекта является константным x.n2=4;// ok, mutable элемент константного объекта не является константой   constint& r1 = n1;// ссылка на константу, привязанную к неконстантному объекту// r1 = 2; // ошибка: попытка изменить через ссылку на constconst_cast<int&>(r1)=2;// ok, изменяет неконстантный объект n1   constint& r2 = n2;// ссылка на константу, привязанную к константному объекту// r2 = 2; // ошибка: попытка изменить через ссылку на const// const_cast<int&>(r2) = 2; // поведение неопределено: попытка изменить// константный объект n2   [](...){}(n3, n4, x, r2);// смотрите также: [[maybe_unused]]   std::system("g++ -O3 -Wa,-adhln ./main.cpp");// может выдавать asm в системах POSIX}

Возможный вывод:

# типичный машинный код, созданный на платформе x86_64 # (генерируется только тот код, который способствует наблюдаемым побочным эффектам) main: movl $0, -4(%rsp) # volatile int n4 = 0; movl $3, -4(%rsp) # n4 = 3; xorl  %eax, %eax # возвращает 0 (неявно) ret

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 1428 C++98 определение константного объекта было основано на объявлении основано на типе объекта
CWG 1528 C++98 неограниченное количество вхождений каждого cv-квалификатора
в одной и той же последовательности cv-квалификаторов
не более одного раза для каждого
cv-квалификатора
CWG 1799 C++98 mutable может быть применён к элементам данных, не
объявленным как const, но типы элементов могут по-прежнему
иметь const-квалификацию
не может применять mutable к элементам
данных const-квалифицированных типов

[править]Смотрите также

Документация C по Квалификатор const
Документация C по Квалификатор volatile
close