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

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

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
if
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор 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
Выделение памяти
Классы
Свойства функции класса
explicit (C++11)
static
Специальные функции-элементы
Шаблоны
Разное
 
Обьявления
Объявления
ссылка
указатель
массив
Block declarations
простое объявление
объявление структурных привязок (C++17)
объявление псевдонимов(C++11)
объявление псевдонимов пространств имён
using-declaration
директива using
объявление static_assert (C++11)
определение asm
объявление непрозрачного enum(C++11)
Другие объявления
определение пространств имён
объявление функции
объявление шаблона класса
объявление шаблона функции
явное инстанцирование шаблона(C++11)
явная специализация шаблона
спецификация связывания
объявление атрибута (C++11)
пустое объявление
 

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

  • 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-квалификаторов. Например, const const и volatile const volatile не являются допустимыми последовательностями cv-квалификаторов.

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

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

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

class X
{
    mutable const int* 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
  • неквалифицированный < const volatile
  • const < const volatile
  • volatile < const volatile

Ссылки и указатели на 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;          // неконстантный объект
    const int n2 = 0;    // константный объект
    int const n3 = 0;    // константный объект (то же что и n2)
    volatile int n4 = 0; // volatile объект
 
    const struct
    {
        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 элемент константного объекта не является константой
 
    const int& r1 = n1; // ссылка на константу, привязанную к неконстантному объекту
//  r1 = 2; // ошибка: попытка изменить через ссылку на const
    const_cast<int&>(r1) = 2; // ok, изменяет неконстантный объект n1
 
    const int& 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