WikiSort.ru - Программирование

ПОИСК ПО САЙТУ | о проекте

В языках программирования C, C++, и D const является квалификатором типа:[lower-alpha 1] ключевое слово применяется к типу данных, показывая, что данные константны (неизменяемы). Это может быть использовано при объявлении (декларировании) констант. Отличительная особенность const в C-подобных языках программирования проявляется при его комбинировании с типами данных, что дает сложное поведение в сочетании с указателями, ссылками, составными типами данных и при проверке типов.

Введение

При объявлении[lower-alpha 2] объектов с использованием const их значения константны (неизменяемы), в отличие от перeменных. Этот основной сценарий использования — объявление констант — имеет параллели во многих языках.

Однако в отличие от других языков в семье языков C const является частью типа, а не объекта. Например, в C const int x = 1; объявляет объект x типа const int, где const — часть типа. Это может читаться «(const int) x» — в то время как в Ada X : constant INTEGER := 1_ объявляет константу (вид объекта) X типа INTEGER, т. е. constant является частью объекта, а не типа.

Появляются два тонких момента. Во-первых, const может быть частью более сложных типов. Например, int const * const x; (выражение читается от переменной x в противоположную сторону) объявляет константный указатель на константное целое число, в то время как int const * x; объявляет переменную-указатель на константное целое, а int * const x; объявляет константный указатель на переменное целое. Во-вторых, поскольку const является частью типа, это используется при проверке типов. Например, следующий код некорректен:

void f(int& x);
//...
const int i;
f(i);

потому что аргумент, передаваемый в f, должен быть ссылочной переменной на целое, а i — константное целое. Требование такого соответствия — форма обеспечения правильности программы, также известное как const-овая правильность (англ. const-correctness). Это дает возможность контрактного проектирования, где у функций в качестве части сигнатуры типа указывается, будут ли они изменять свои аргументы или нет, и изменяемы (неконстантны) ли их возвращаемые значения. Такая проверка типов интересна прежде всего для указателей и ссылок (т. е. когда параметры передаются по ссылке) — а не для основных типов, таких как целые, — а также для составных типов данных или шаблонизированных типов, таких как контейнеры. Вследствие неявного преобразования типов при выполнении программы const может быть опущен.

Следствия

Константность переменной не накладывает на переменную при сохранении в памяти компьютера ограничения на запись. const — это скорее конструкция времени компиляции, которую программист потенциально может использовать, однако это необязательно. Заметим, однако, что в случае предопределенных строковых литералов (таких как const char *) const-переменная в C обычно неперезаписываема.

Другие варианты использования

В дополнение к этому как const может быть объявлена функция-член (нестатическая). В этом случае указатель this внутри такой функции будет иметь тип object_type const * const вместо object_type * const. Это означает, что неконстантные по отношению к этому объекту функции изнутри такой функции вызваны быть не могут, также не могут быть модифицированы поля класса. В C++ поле класса может быть объявлено как mutable (изменяемое), что означает, что это ограничение к нему не относится. В некоторых случаях это может быть полезно, например, при кешировании, подсчёте ссылок и синхронизации данных. В этих случаях логический смысл (состояние) объекта неизменяем, но объект физически неконстантен, так как его поразрядное представление может измениться.

Синтакс

В C, C++, и D все типы данных, включая те, которые определены пользователем, могут быть объявлены const, и «const-овая правильность» предполагает, что все переменные или объекты должны быть объявлены таковыми, если их не нужно модифицировать. Такое предусмотрительное использование const делает значения переменных "простыми для понимания, отслеживания, и обдумывания"[1], таким образом, читаемость и понятность увеличиваются и делают работу в командах и поддержку кода проще, потому что это предоставляет информацию о надлежащем использовании их значений. Это может помочь компилятору так же, как и разработчику при размышлениях над кодом. Это также может позволить оптимизирующему компилятору генерировать более эффективный код[2].

Простые типы данных

Для простых типов данных (неуказателей) применение квалификатора const очевидно. Его можно указывать с любой стороны типа по историческим причинам (const char foo = 'a'; эквивалентно char const foo = 'a';). В некоторых реализациях использование const с двух сторон типа (например, const char const) генерирует предупреждение, но не ошибку.

Указатели и ссылки

Для указателей и ссылок результирующий эффект const более запутанн: и сам указатель, и значение, на которое он указывает, или оба могут быть объявлены как const. Более того, синтаксис также может сбивать с толку.

Указатель может быть объявлен const-указателем на перезаписываемое значение (type * const x;), или перезапысываемым указателем на const-значение (type const * x; //или: const type * x;), или const-указателем на const-значение (type const * const x;). const-указателю нельзя переприсвоить ссылку на другой объект с первоначального, но он (указатель) может быть использован для изменения значения, на которое он указывает (такое значение называется «значение по указателю» (англ. pointee)). Таким образом, синтаксис ссылочных переменных — альтернативный синтакс const-указателей. С другой стороны, указателю на const-объект можно переприсвоить ссылку для указания на другую область памяти (которая должна содержать объект того же или приводимого типа), но его нельзя будет использовать, чтобы менять значения в памяти, на которые он указывает. Также может быть определен const-указатель на const-объект, который нельзя использовать, чтобы изменять значение по нему, и которому нельзя переприсвоить ссылку на другой объект.

Эти тонкости иллюстрирует следующий код:

void Foo (
 int * ptr,
 int const * ptrToConst,
 int * const constPtr,
 int const * const constPtrToConst)
{
    *ptr = 0; //Порядок: меняет данные по указателю.
    ptr = NULL; //Порядок: меняет указатель.
    
    *ptrToConst = 0; //Ошибка! Нельзя менять данные по указателю.
    ptrToConst = NULL; //Порядок: меняет указатель.
    
    *constPtr = 0; //Порядок: меняет данные по указателю.
    constPtr  = NULL; //Ошибка! Нельзя менять указатель.
    
    *constPtrToConst = 0; //Ошибка! Нельзя менять данные по указателю.
    constPtrToConst  = NULL; //Ошибка! Нельзя менять указатель.
}

Соглашения по записи в языке C

В соответствие с обычными соглашениями языка Си об объявлениях последние указываются за предполагаемым использованием, а звёздочка у указателя к нему ставится вплотную, указывая на разыменование. Например, в объявлении int *ptr разыменованная форма *ptr является целым (int), а ссылочная форма ptr — указателем на целое. Таким образом, const модифицирует имя переменной справа от себя.

Соглашение в языке Си++ наоборот, связывать * с типом (т. е. int* ptr) и читать, что const модифицирует тип слева от себя. Поэтому int const * ptrToConst можно прочитать или как «*ptrToConst это int const» (значение по указателю неизменяемо), или как «ptrToConst это int const *» (указатель на неизменяемое целое значение).

Таким образом:

int *ptr; //"*ptr" -- целое значение.
int const *ptrToConst; //"*ptrToConst" -- константа ("int" -- целая).
int * const constPtr; //"constPtr" -- константа ("int *" -- указатель на целое).
int const * const constPtrToConst; //"constPtrToConst" -- константа (указатель),
                                   //как и "*constPtrToConst" (значение).

Примечания

  1. In D the term type constructor is used instead of type qualifier, by analogy with constructors in object-oriented programming.
  2. Formally when the const is part of the outermost derived type in a declaration; pointers complicate discussion.
  1. Herb Sutter and Andrei Alexandrescu (2005).
  2. Why is the kfree() argument const?. lkml.org (12 января 2013).

Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".

Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.

Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .




Текст в блоке "Читать" взят с сайта "Википедия" и доступен по лицензии Creative Commons Attribution-ShareAlike; в отдельных случаях могут действовать дополнительные условия.

Другой контент может иметь иную лицензию. Перед использованием материалов сайта WikiSort.ru внимательно изучите правила лицензирования конкретных элементов наполнения сайта.

2019-2024
WikiSort.ru - проект по пересортировке и дополнению контента Википедии