Адская смесь, надо сказать. Довольно неприятный и не интуитивный момент в C/C++.
Итак, в чём суть проблемы: есть программа
Казалось бы, это не должно компилироваться, ведь мы константному объекту присваиваем значение. Но фишка в том что объект не константен.
Почему так происходит? Для начала посмотрим что есть typedef (C11 draft):
Если рассматривать процесс парсинга объявлений, то грубо говоря, он происходит справа налево, причём модификатор применяется к тому типу, рядом с которым находится. Поясню на примере. Если у нас есть строка вида
то читать её следует как объект a типа указатель на char, который неизменяем, что равносильно строке
А вот если есть строка вида
то читается она как объект a типа неизменяемый указатель на char. Т.о. сам char мы вполне можем поменять.
Теперь посмотрим как читается строка с типом, определённым через typedef:
объект b неизменяемого типа string. Что есть string? Указатель на char. В итоге получаем неизменяемый указатель на изменяемый char. Это эквивалентно выражению
Такая вот метаморфоза происходит. С точки зрения компилятора - всё просто и логично. С точки зрения человека, впервые столкнувшегося с этим - единственная мысль: "WTF?"
Итак, в чём суть проблемы: есть программа
#include <stdlib.h>
int main()
{
typedef char * string;
string a = "hello";
const string b = "world \n";
a[4] = ' ';
b[5] = '!';
}
Казалось бы, это не должно компилироваться, ведь мы константному объекту присваиваем значение. Но фишка в том что объект не константен.
Почему так происходит? Для начала посмотрим что есть typedef (C11 draft):
6.7.8 Type definitions
3. ... A typedef declaration does not introduce a new type, only aЧто означает, что typedef не создаёт тип, а просто прописывает для него новое имя. Это справедливо как для всех стандартов C, так и для C++. И самый очевидный вопрос: почему объект типа
synonym for the type so specified.
const string
не является константным?Если рассматривать процесс парсинга объявлений, то грубо говоря, он происходит справа налево, причём модификатор применяется к тому типу, рядом с которым находится. Поясню на примере. Если у нас есть строка вида
const char * a = "hello";
то читать её следует как объект a типа указатель на char, который неизменяем, что равносильно строке
char const * a = "hello";
А вот если есть строка вида
char * const a = "hello";
то читается она как объект a типа неизменяемый указатель на char. Т.о. сам char мы вполне можем поменять.
Теперь посмотрим как читается строка с типом, определённым через typedef:
const string b = "world \n";
объект b неизменяемого типа string. Что есть string? Указатель на char. В итоге получаем неизменяемый указатель на изменяемый char. Это эквивалентно выражению
char * const
b = "world \n";
Такая вот метаморфоза происходит. С точки зрения компилятора - всё просто и логично. С точки зрения человека, впервые столкнувшегося с этим - единственная мысль: "WTF?"
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.