c++ функции алена - В чем разница между const int *, const int * const и int const *?





7 Answers

Для тех, кто не знает о правиле по часовой стрелке / спирали: начните с имени переменной, перемещайте по часовой стрелке (в данном случае, переместитесь назад) к следующему указателю или типу . Повторяйте до окончания выражения.

вот демо:

char что это

Я всегда испортил, как правильно использовать const int* , const int * const и int const * . Существует ли набор правил, определяющих, что вы можете и чего не можете сделать?

Я хочу знать все дела, и все это не касается заданий, передачи функций и т. Д.




Как и многие, все отметили:

В чем разница между const X* p , X* const p и const X* const p ?

Вы должны прочитать декларации указателей справа налево.

  • const X* p означает «p указывает на X, который является const»: объект X не может быть изменен через p.

  • X* const p означает, что «p - это указатель на const, который не является const»: вы не можете изменить указатель p, но вы можете изменить объект X через p.

  • const X* const p означает, что «p - это указатель const на X, который является const»: вы не можете изменить указатель p самостоятельно, и вы не можете изменить объект X через p.




Этот вопрос точно показывает, почему мне нравится делать то, о чем я упомянул в своем вопросе, является константа после допустимого типа id?

Короче говоря, я считаю, что самый простой способ запомнить правило состоит в том, что «const» идет за тем, к чему он относится. Поэтому в вашем вопросе «int const *» означает, что int является константой, а «int * const» означает, что указатель является постоянным.

Если кто-то решает поставить его на передний план (например: «const int *»), в качестве особого исключения в этом случае он применяется к предмету после него.

Многие люди любят использовать это специальное исключение, потому что считают, что это выглядит лучше. Мне это не нравится, потому что это исключение и, таким образом, путает вещи.




Простое использование 'const'

Самое простое использование - объявить именованную константу. Для этого один объявляет константу, как если бы она была переменной, но добавляла 'const' перед ней. Нужно немедленно инициализировать его в конструкторе, потому что, конечно, нельзя установить значение позже, так как это изменит его. Например,

const int Constant1=96; 

создаст целочисленную константу, невообразимо названную «Константа1» со значением 96.

Такие константы полезны для параметров, которые используются в программе, но их не нужно менять после компиляции программы. Он имеет преимущество для программистов над командой «#define» препроцессора C, поскольку он понимается и используется самим компилятором, а не просто заменяется текстом программы препроцессором до достижения основного компилятора, поэтому сообщения об ошибках гораздо полезнее ,

Он также работает с указателями, но нужно быть осторожным, когда «const» определяет, является ли указатель или то, на что он указывает, постоянным или и тем, и другим. Например,

const int * Constant2 

объявляет, что Constant2 является указателем переменной на постоянное целое число и

int const * Constant2

является альтернативным синтаксисом, который делает то же самое, тогда как

int * const Constant3

объявляет, что Constant3 является постоянным указателем на переменное целое число и

int const * const Constant4

объявляет, что Constant4 является постоянным указателем на постоянное целое число. В основном «const» применяется к тому, что находится на его непосредственном левом (кроме если нет ничего там, в этом случае оно относится ко всему, что является его непосредственным правом).

ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html




В C ++ есть много других тонких точек, окружающих константную корректность. Я предполагаю, что вопрос здесь просто о C, но я приведу некоторые связанные примеры, поскольку тег - это C ++:

  • Вы часто передаете большие аргументы, такие как строки, как TYPE const & которые не позволяют объекту либо модифицироваться, либо копироваться. Пример :

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Но TYPE & const имеет смысла, поскольку ссылки всегда const.

  • Вы всегда должны указывать методы класса, которые не изменяют класс как const , иначе вы не можете вызвать метод из TYPE const & ссылки. Пример :

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Существуют общие ситуации, когда как возвращаемое значение, так и метод должны быть const. Пример :

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    На самом деле, методы const не должны возвращать внутренние данные класса как ссылку на не-const.

  • В результате часто приходится создавать как const, так и неконстантный метод с использованием перегрузки const. Например, если вы определяете T const& operator[] (unsigned i) const; , то вам, вероятно, также захочется неконстантная версия, заданная:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, в C нет функций const, функции нечлена не могут быть const в C ++, методы const могут иметь побочные эффекты, а компилятор не может использовать функции const, чтобы избежать дублирования вызовов функций. На самом деле даже простой int const & reference может свидетельствовать о том, что значение, к которому оно относится, должно быть изменено в другом месте.




Синтаксис объявления C и C ++ неоднократно описывался как неудачный эксперимент, оригинальные дизайнеры.

Вместо этого давайте назовем тип «указатель на Type »; Я назову это Ptr_ :

template< class Type >
using Ptr_ = Type*;

Теперь Ptr_<char> является указателем на char .

Ptr_<const char> является указателем на const char .

И const Ptr_<const char> является const Ptr_<const char> указателем на const char .

Там.




В основном это касается второй строки: лучшие практики, назначения, параметры функций и т. Д.

Общая практика. Постарайтесь сделать все, что вы можете. Или, чтобы поместить этот другой путь, сделайте все const для начала, а затем удалите точно минимальный набор const необходимый, чтобы позволить программе функционировать. Это будет большой помощью в достижении const-correctness и поможет гарантировать, что тонкие ошибки не будут введены, когда люди попытаются назначить вещи, которые они не должны изменять.

Избегайте const_cast <> как чума. Для него есть один или два законных варианта использования, но их очень мало и далеко друг от друга. Если вы пытаетесь изменить объект const , вы сделаете намного лучше, чтобы тот, кто объявил его const в первом темпе, и поговорил с ним, чтобы достичь консенсуса относительно того, что должно произойти.

Это очень точно относится к заданиям. Вы можете назначить что-то только в том случае, если оно не const. Если вы хотите назначить что-то, что является константой, см. Выше. Помните, что в объявлениях int const *foo; и int * const bar; разные вещи - const - другие ответы здесь очень хорошо освещали эту проблему, поэтому я не буду в нее входить.

Функциональные параметры:

Переходите по значению: например, void func(int param) вам не важно, так или иначе на вызывающем сайте. Аргумент может заключаться в том, что существуют случаи использования для объявления функции как void func(int const param) но это не влияет на вызывающего, только на самой функции, поскольку любое переданное значение не может быть изменено функцией во время вызов.

Передайте по ссылке: например, void func(int &param) Теперь это имеет значение. Как только объявлено func , разрешено изменять param , и любой вызывающий сайт должен быть готов справиться с последствиями. Изменение декларации на void func(int const &param) изменяет контракт и гарантирует, что func теперь не может изменять param , то есть то, что передается, - это то, что вернется. Как отмечали другие, это очень полезно для дешевой передачи большого объекта, который вы не хотите изменять. Передача справки намного дешевле, чем передача большого объекта по значению.

Pass by pointer: например, void func(int *param) и void func(int const *param) Эти два довольно синонимичны с их ссылочными аналогами, с оговоркой, что вызываемая функция теперь должна проверять значение nullptr если какая-либо другая договорная гарантия гарантирует, что он никогда не получит значение nullptr в param .

Мнение на эту тему. Доказательство правильности в таком случае адски сложно, просто слишком легко сделать ошибку. Поэтому не рискуйте и всегда проверяйте параметры указателя для nullptr . Вы избавитесь от боли и страданий и сможете найти ошибки в долгосрочной перспективе. А что касается стоимости чека, то это дешево, и в тех случаях, когда статический анализ, встроенный в компилятор, может управлять им, оптимизатор все равно его удалит. Включите генерацию временного кода канала для MSVC или WOPR (я думаю) для GCC, и вы получите его в виде программы, т. Е. Даже в вызовах функций, пересекающих границу модуля исходного кода.

В конце дня все вышеизложенное делает очень надежный случай, когда всегда предпочитают ссылки на указатели. Они все безопаснее.




Related