Spec-Zone.ru › C++

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

Используются в любом спецификаторе типа, включая decl-specifier-seq в грамматике объявлений, чтобы указать константность или volatile-квалификацию объявляемого объекта или именуемого типа.

  • const — указывает, что тип является константным.
  • volatile — указывает, что тип является volatile.

Пояснение

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

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

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

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

Объекты const и volatile

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

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

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

Спецификатор mutable

  • mutable — разрешает изменять объявленный как mutable член класса, даже если содержащий его объект объявлен как const (то есть член класса является изменяемым).

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

class X
{
    mutable const int* p; // OK
    mutable int* const q; // ill-formed
    mutable int&       r; // ill-formed
};

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

class ThreadsafeCounter
{
    mutable std::mutex m; // The "M&M rule": mutable and mutex go together
    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, которая не является не-шаблоном(начиная с C++14)не-inline(начиная с C++17) и не объявлена как extern, задаёт ей внутреннее связывание. Это отличается от C, где переменные const с областью видимости файла имеют внешнее связывание.

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

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

  • lvalue volatile-типа в качестве операнда встроенных операторов инкремента/декремента;
  • lvalue volatile-типа в качестве левого операнда встроенного присваивания, если только выражение прямого присваивания не находится в невычисляемом контексте или не является выражением с отбрасываемым значением;
  • тип объекта volatile в качестве типа параметра или возвращаемого значения функции;
  • квалификатор volatile в объявлении структурированной привязки.
(начиная с C++20)

Ключевые слова

const, volatile, mutable

Пример

#include <cstdlib>

int main()
{
    int n1 = 0;          // non-const object
    const int n2 = 0;    // const object
    int const n3 = 0;    // const object (same as n2)
    volatile int n4 = 0; // volatile object
    
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};        // const object with mutable member
    
    n1 = 1;   // OK: modifiable object
//  n2 = 2;   // error: non-modifiable object
    n4 = 3;   // OK: treated as a side-effect
//  x.n1 = 4; // error: member of a const object is const
    x.n2 = 4; // OK: mutable member of a const object isn't const
    
    const int& r1 = n1; // reference to const bound to non-const object
//  r1 = 2; // error: attempt to modify through reference to const
    const_cast<int&>(r1) = 2; // OK: modifies non-const object n1
    
    const int& r2 = n2; // reference to const bound to const object
//  r2 = 2; // error: attempt to modify through reference to const
//  const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
    
    [](...){}(n3, n4, x, r2); // see also: [[maybe_unused]]
    
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // may issue asm on POSIX systems
}

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

# typical machine code produced on an x86_64 platform
# (only the code that contributes to observable side-effects is emitted)
main:
    movl    $0, -4(%rsp) # volatile int n4 = 0;
    movl    $3, -4(%rsp) # n4 = 3;
    xorl    %eax, %eax   # return 0 (implicit)
    ret

Отчёты об исправлениях

Следующие отчёты об исправлениях, изменяющих поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

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

См. также

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/cv

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API