Для начала вы, вероятно, знаете, что с const
его помощью можно сделать либо данные объекта, либо указатель неизменяемыми, либо и то, и другое.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Однако вы также можете использовать синтаксис:
Object const *obj; // same as const Object* obj;
Единственное, что кажется важным, - это то, с какой стороны звездочки вы помещаете const
ключевое слово. Лично я предпочитаю ставить const
слева от типа, чтобы указать, что данные не подлежат изменению, поскольку я считаю, что он лучше читается в моем мышлении слева направо, но какой синтаксис появился первым?
Что еще более важно, почему существует два правильных способа указания const
данных и в какой ситуации вы бы предпочли или понадобились бы один другому, если таковой имеется?
Редактировать:
Похоже, это было произвольное решение, когда стандарт того, как компиляторы должны интерпретировать вещи, был разработан задолго до моего рождения. Поскольку const
применяется к тому, что находится слева от ключевого слова (по умолчанию?) Я думаю, они решили, что добавление «ярлыков» для применения ключевых слов и квалификаторов типов другими способами не повредит, по крайней мере, до тех пор, пока объявление не изменится на разбор * или & ...
Полагаю, так было и в C?
const
после типа, например,#define MAKE_CONST(T) T const
вместо,#define MAKE_CONST(T) const T
чтобыMAKE_CONST(int *)
правильно расширить доint * const
вместоconst int *
.Ответы:
По сути, причина того, что положение
const
спецификаторов внутри перед звездочкой не имеет значения, заключается в том, что грамматика C была определена таким образом Керниганом и Ричи.Причина, по которой они определили грамматику таким образом, заключалась в том, что их компилятор C анализировал ввод слева направо и завершал обработку каждого токена по мере его использования. Использование
*
токена изменяет состояние текущего объявления на тип указателя. Встречаconst
после*
означает, чтоconst
квалификатор применяется к объявлению указателя; обнаружение его до того,*
как квалификатор применяется к указанным данным.Поскольку семантическое значение не изменяется, если
const
квалификатор появляется до или после спецификаторов типа, он принимается в любом случае.Аналогичный случай возникает при объявлении указателей на функции, где:
void * function1(void)
объявляет функцию, которая возвращаетvoid *
,void (* function2)(void)
объявляет указатель функции на возвращаемую функциюvoid
.Снова следует отметить, что синтаксис языка поддерживает синтаксический анализатор слева направо.
источник
*
синтаксический анализатор компилятора не узнает, что это указатель, он является константой для значения данных. После * это относится к постоянному указателю. Блестяще. И, наконец, это объясняет, почему я умею такconst char
же хорошоchar const
.const
чтобы объект всегда шел после того, что он квалифицирует ... именно так, чтобы я всегда мог завершить обработку константы сразу после ее использования. Так что, похоже, это аргумент в пользу запрета west-const, а не разрешения.++
оператор? «Приговор», imho, помог мне понять, что не было никакой особой причины, кроме того, что они могли. Может быть, сегодня они сделают другой выбор, а может, и нет.Правило такое:
Я предпочитаю использовать const справа от объекта, чтобы быть const только потому, что это «оригинальный» способ определения const.
Но я считаю, что это очень субъективная точка зрения.
источник
Object const *
, это указатель на объект const. Если вы поместитеconst
слева, он будет считаться указателем на объект, который является const, что на самом деле не очень хорошо работает.const
это не класс хранилища, но люди не парсеры).Я предпочитаю второй синтаксис. Это помогает мне отслеживать "что" постоянно, читая объявление типа справа налево:
Object * const obj; // read right-to-left: const pointer to Object Object const * obj; // read right-to-left: pointer to const Object Object const * const obj; // read right-to-left: const pointer to const Object
источник
Object const* const
нетconst const Object*
. «const» не может быть слева, за исключением особого случая, когда это очень нравится многим людям. (См. Heath выше.)Порядок ключевых слов в объявлении не так уж и фиксирован. Есть много альтернатив «единому истинному порядку». Как это
int long const long unsigned volatile i = 0;
или должно быть
volatile unsigned long long int const i = 0;
??
источник
decl-specifier-seq
- это последовательностьdecl-specifier
s. В грамматике нет порядка, и количество вхождений для каждого ключевого слова ограничено только некоторыми семантическими правилами (у вас может быть одно,const
но дваlong
:-)unsigned
это тип, такой же, какunsigned int
иint unsigned
.unsigned long
это другой тип, такой же, какunsigned long int
иint long unsigned
. Видите узор?;)
. ОК, спасибоstatic
к беспорядку слов, но только недавно компиляторы жаловались, чтоstatic
нужно идти первым.Первое правило - использовать тот формат, который требуется в соответствии с вашими местными стандартами кодирования. После этого:
const
вставка вперед приводит к бесконечной путанице, когда задействованы определения типов, например:typedef int* IntPtr; const IntPtr p1; // same as int* const p1;
Если ваш стандарт кодирования допускает typedef указателей, то он действительно должен настаивать на том, чтобы после типа помещалась константа. В любом случае, кроме применения к типу, константа должна следовать за тем, к чему она применяется, поэтому согласованность также свидетельствует в пользу константы после. Но местные правила кодирования важнее всего этого; разница обычно не настолько важна, чтобы вернуться и изменить весь существующий код.
источник
const std::string::const_iterator
также для хорошей меры;)const IntPtr p1
означать, кроме «постоянный указатель на целое число» (т.е. «постоянный указатель на целое число»)? Никто в здравом уме, даже не зная, какIntPtr
определяется, не мог бы подумать, чтоp1
это изменчиво. И в этом отношении, почему кто-то может ошибочно предполагать, что*p1
это неизменяемое? Более того, размещение константы в другом месте (например,IntPtr const p1
) вообще не меняет семантику.std::vector<T>::const_iterator
, где константен не итератор, а то, на что он указывает).Есть исторические причины, по которым приемлемо либо левое, либо правое. Страуструп добавил const в C ++ к 1983 году , но до C89 / C90 он не попал в C.
В C ++ есть веская причина всегда использовать const справа. Вы будете последовательны везде, потому что функции-члены const должны быть объявлены следующим образом:
int getInt() const;
источник
const int& getInt();
int& const getInt();
int const& getInt();
лучше, чем эквивалент,const int& getInt();
тогда какint& const getInt();
то, с чем вы его сравниваете, является избыточным (ссылки уже являются константными), хотя законно и обычно дает предупреждение. В любом случае, const в функции-члене изменяетthis
указатель в функции сFoo* const
наFoo const* const
.const
в функции-члене означает совсем не одно и то же - или этоvoid set(int)&;
какая-то ссылка на функцию?C использует синтаксис с написанием справа налево. Просто прочтите объявления справа налево:
int var = 0; // one is a pointer to a const int int const * one = &var; // two is a pointer to an int const (same as "const int") const int * two = &var; // three is a constant pointer to an int int * const three = &var;
Это влияет на первое, что осталось от "const".
Чтобы получить больше удовольствия, прочтите это руководство: http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html
источник