Interested Article - Const (программирование)

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

Введение

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

Синтаксис

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

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

Для простых типов данных (неуказателей) применение квалификатора 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. lkml.org (12 января 2013). Дата обращения: 9 января 2016. Архивировано из 4 марта 2016 года.
Источник —

Same as Const (программирование)