Поделиться через


Указатели const и volatile

Ключевые слова const и volatile изменяют способы обработки указателей. Ключевое слово const указывает, что указатель невозможно изменить после инициализации; он защищен от последующих изменений.

Ключевое слово volatile указывает, что значение, связанное с указанным после него именем, может быть изменено различными действиями (но не через пользовательское приложение). Таким образом, ключевое слово volatile полезно для объявления объектов в общей памяти, обращаться к которым могут несколько процессов или глобальных областей данных, используемых для обмена данными с процедурами службы прерываний.

Если имя объявляется как volatile, то каждый раз, когда программа обращается к значению, компилятор перезагружает его из памяти. Это значительно сокращает возможности оптимизации. Однако если состояние объекта может неожиданно изменяться, то это единственный способ гарантировать предсказуемую производительность программы.

Чтобы объявить объект указателя как const или volatile, используйте объявление следующего вида:

const char *cpch;
volatile char *vpch;

Чтобы объявить значение указателя, т. е. фактически хранящийся в нем адрес, как const или volatile, используйте объявление следующего вида:

char * const pchc;
char * volatile pchv;

Язык C++ предотвращает присваивания, которые могут допустить изменение объекта или указателя, объявленного как const. Такие присваивания могут удалить информацию, с которой был объявлен объект или указатель, и тем самым подменить смысл исходного объявления. Рассмотрим следующее объявление:

const char cch = 'A';
char ch = 'B';

Учитывая приведенные выше объявления двух объектов (cch типа const char и ch типа char), здесь допускаются следующие объявления и инициализации:

const char *pch1 = &cch;
const char *const pch4 = &cch;
const char *pch5 = &ch;
char *pch6 = &ch;
char *const pch7 = &ch;
const char *const pch8 = &ch;

Следующие объявления и инициализации вызывают ошибки.

char *pch2 = &cch;   // Error
char *const pch3 = &cch;   // Error

В объявлении pch2 задается указатель, при помощи которого может быть изменен постоянный объект, поэтому это объявление запрещено. В объявлении pch3 указано, что постоянным является не объект, а указатель (параметр pointer). Это объявление запрещено по той же причине, что и объявление pch2.

В следующих восьми примерах демонстрируется присваивание через указатель и изменение значения указателя для приведенных выше объявлений. Здесь мы предполагаем, что инициализация указателей pch1–pch8 была выполнена без ошибок.

*pch1 = 'A';  // Error: object declared const
pch1 = &ch;   // OK: pointer not declared const
*pch2 = 'A';  // OK: normal pointer
pch2 = &ch;   // OK: normal pointer
*pch3 = 'A';  // OK: object not declared const
pch3 = &ch;   // Error: pointer declared const
*pch4 = 'A';  // Error: object declared const
pch4 = &ch;   // Error: pointer declared const

Указатели, объявленные как volatile или как const и volatile одновременно, подчиняются тем же правилам.

Указатели на объекты const часто используются в объявлениях функций. Это делается следующим образом:

errno_t strcpy_s( char *strDestination, size_t numberOfElements, const char *strSource );

В приведенной выше инструкции объявляется функция strcpy_s, в которой два из трех аргументов являются указателями на переменную типа char. Так как аргументы передаются по ссылке, а не по значению, то функция могла бы свободно изменить и strDestination, и strSource, если бы указатель strSource не был объявлен как const. Но поскольку указатель strSource объявлен как const, вызывающий объект определяет, что вызываемая функция не может изменить strSource.

Примечание

Поскольку имя-типа * стандартно преобразуется в константное имя-типа *, то функции strcpy_s можно передавать аргументы типа символ *.Однако обратное неверно; преобразования, позволяющего удалить атрибут const из объекта или указателя, не существует.

Указатель const заданного типа можно присвоить указателю того же типа. Однако указатель без атрибута const не может быть присвоен указателю с атрибутом const. В следующем коде показано одно верное и одно неверное присваивание.

// const_pointer.cpp
int *const cpObject = 0;
int *pObject;

int main() {
pObject = cpObject;
cpObject = pObject;   // C3892
}

В следующем примере показано, как объявить объект как const, когда имеется указатель на указатель на объект.

// const_pointer2.cpp
struct X {
   X(int i) : m_i(i) { }
   int m_i;
};

int main() {
   // correct
   const X cx(10);
   const X * pcx = &cx;
   const X ** ppcx = &pcx;

   // also correct
   X const cx2(20);
   X const * pcx2 = &cx2;
   X const ** ppcx2 = &pcx2;
}

См. также

Ссылки

Указатели