понедельник, 24 сентября 2012 г.

typedef и const

Адская смесь, надо сказать. Довольно неприятный и не интуитивный момент в C/C++.
Итак, в чём суть проблемы: есть программа

#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
synonym for the type so specified.
Что означает, что typedef не создаёт тип, а просто прописывает для него новое имя. Это справедливо как для всех стандартов C, так и для C++. И самый очевидный вопрос: почему объект типа 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?"

Комментариев нет:

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.