Namespaces
Variants

cv ( const and volatile ) type qualifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

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

Содержание

Объяснение

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

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

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

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

Константные и волатильные объекты

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

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

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

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 не- template (since C++14) не- inline (since C++17) переменной, которая не объявлена как extern , придает ей внутреннюю линковку . Это отличается от C, где const переменные на уровне файла имеют внешнюю линковку.

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

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

(since C++20)

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

const , volatile , mutable

Пример

#include <cstdlib>
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_cast<int&>(r1) = 2; // OK: изменяет неконстантный объект n1
    const int& r2 = n2; // ссылка на константу, привязанная к константному объекту
//  r2 = 2; // ошибка: попытка изменения через ссылку на константу
//  const_cast<int&>(r2) = 2; // неопределенное поведение: попытка изменения константного объекта n2
    [](...){}(n3, n4, x, r2); // см. также: [[maybe_unused]]
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // может вывести ассемблерный код на POSIX системах
}

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

# типичный машинный код, сгенерированный на платформе x86_64
# (выводится только код, вносящий вклад в наблюдаемые побочные эффекты)
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 определение 'const object' основывалось на объявлении основывается на типе объекта
CWG 1528 C++98 не было требований к количеству вхождений
каждого cv-квалификатора в одной последовательности cv-квалификаторов
не более одного раза для
каждого cv-квалификатора
CWG 1799 C++98 mutable мог применяться к элементам данных, не объявленным
const , но типы элементов всё равно могли быть квалифицированы как const
нельзя применять mutable к элементам
данных типов, квалифицированных как const

Смотрите также

C documentation для const квалификатора
C documentation для volatile квалификатора