В чем разница между константный инт*, константный тип int * const и int строительства *?

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

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

14 ответов


прочитайте его назад (как управляется По Часовой Стрелке / Спиральное Правило):

  • int* - указатель на int
  • int const * - указатель на const int
  • int * const - const указатель на int
  • int const * const - const указатель на const int

первое const может быть по обе стороны от типа так:

  • const int * ==int const *
  • const int * const == int const * const

если вы хотите сойти с ума, вы можете сделать такие вещи:

  • int ** - указатель на указатель на int
  • int ** const - указатель const на указатель на int
  • int * const * - указатель на указатель const на int
  • int const ** - указатель на указатель на const int
  • int * const * const - указатель const на указатель const на int
  • ...

и чтобы убедиться, что мы ясно понимаем значение const

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

foo - это переменная-указатель на постоянное целое число. Это позволяет изменить то, на что вы указываете, но не значение, на которое вы указываете. Чаще всего это видно со строками в стиле C, где у вас есть указатель на const char. Вы можете изменить строку, на которую указываете, но вы не можете изменить содержимое этих строк. Это важно, когда сама строка в сегмент данных программы и не должен быть изменен.

bar постоянный или фиксированный указатель на значение, которое может быть изменено. Это похоже на ссылку без дополнительного синтаксического сахара. Из-за этого факта обычно вы будете использовать ссылку, где вы будете использовать T* const указатель, если вам нужно разрешить NULL указатели.


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

вот демо:

pointer to int

const pointer to int const

pointer to int const

pointer to const int

const pointer to int


Я думаю все уже ответили, но я просто хочу добавить, что вы должны остерегаться typedefs! Это не просто замена текста.

например:

typedef char *ASTRING;
const ASTRING astring;

тип astring и char * const, а не const char *. Это одна из причин, почему я всегда склонен ставить const справа от типа, а не в начале.


как почти все указали:

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

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

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

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

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


  1. постоянные ссылки:

    ссылка на переменную (здесь int), которая является постоянной. Мы передаем переменную как ссылку в основном, потому что ссылки меньше по размеру, чем фактическое значение, но есть побочный эффект, и это потому, что это похоже на псевдоним фактической переменной. Мы можем случайно изменить основную переменную через наш полный доступ к псевдониму, поэтому мы делаем ее постоянной, чтобы предотвратить эту сторону эффект.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. константными указателями

    как только постоянный указатель указывает на переменную, он не может указывать на любую другую переменную.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. указатель на константу

    указатель, через который нельзя изменить значение переменной, на которую он указывает, известен как указатель на константу.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. постоянный указатель на a константа

    постоянный указатель на константу-это указатель, который не может изменить адрес, на который он указывает, и не может изменить значение, хранящееся по этому адресу.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

этот вопрос показывает точно почему мне нравится делать все так, как я упомянул в своем вопросе является ли const после идентификатора типа приемлемым?

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

Если кто-то решит поставить его в очень фронт (например: "const int *"), в качестве специального исключения в этом случае он применяется к вещи после нее.

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


общее правило заключается в том, что const ключевое слово относится к тому, что предшествует ему немедленно. Исключение, начало const относится к следующему.

  • const int* это то же самое, что int const* и означает "указатель на константу типа int".
  • const int* const это то же самое, что int const* const и означает "постоянный указатель на константу int".

Edit: Для DOS и don'TS, если ответ не достаточно, не могли бы вы быть более точными о том, чего вы хотите?


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

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

const int Constant1=96; 

создаст целочисленную константу, невообразимо называемую 'Constant1', со значением 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++ Скотт Мейерс. Обратитесь к третьему пункту в этой книге, где он подробно рассказывает об использовании const.

просто следуйте этому совету

  1. если слово const появляется слева от звездочки, на что указывает константа
  2. если слово const появляется справа от звездочки, сам указатель является константой
  3. если const появляется с обеих сторон оба постоянны

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

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

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

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

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

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

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

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

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

  • в результате часто приходится создавать как метод const, так и метод non-const с использованием перегрузки const. Например, если вы определяете T const& operator[] (unsigned i) const;, тогда вы, вероятно, также захотите версию non-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 & ссылка может засвидетельствовать значение, к которому она относится быть изменены другими.


это просто, но сложно. Обратите внимание, что мы можем поменять const квалификатор с любым типом данных (int, char, float, etc.).

давайте рассмотрим приведенные ниже примеры.


const int *p ==>*p доступно только для чтения [p является указателем на постоянное целое число]

int const *p ==>*p доступно только для чтения [p является указателем на постоянное целое число]


int *p const ==> неправильно заявление. Компилятор выдает синтаксическая ошибка.

int *const p ==> p доступно только для чтения [p является постоянным указателем на целое число]. Как указатель p здесь только для чтения, объявление и определение должны быть в одном месте.


const int *p const ==> неправильно заявление. Компилятор выдает синтаксическую ошибку.

const int const *p ==> *p доступно только для чтения

const int *const p1 ==> *p и p только для чтения [p является постоянным указателем на константу целое.] Как указатель p здесь только для чтения, объявление и определение должны быть в одном месте.


int const *p const ==> неправильно заявление. Компилятор выдает синтаксическую ошибку.

int const int *p ==> неправильно заявление. Компилятор выдает синтаксическую ошибку.

int const const *p ==> *p доступно только для чтения и эквивалентно int const *p

int const *const p ==> *p и p только для чтения [p постоянная указатель на постоянное целое число]. Как указатель p здесь только для чтения, объявление и определение должны быть в одном месте.


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

давайте имя тип "указатель на Type"; Я называю это Ptr_:
template< class Type >
using Ptr_ = Type*;

теперь Ptr_<char> - это указатель на char.

Ptr_<const char> указатель const char.

и const Ptr_<const char> это const указатель на const char.

там.

enter image description here


const с int с обеих сторон сделает указатель на константу типа int.

const int *ptr=&i;

или

int const *ptr=&i;

const после ' * ' сделает постоянный указатель на int.

int *const ptr=&i;

в этом случае все эти указатель на постоянное целое число, но ни один из них не является постоянным указателем.

 const int *ptr1=&i, *ptr2=&j;

в этом случае все указатель на постоянное целое число и ptr2-это постоянный указатель к константе integer. Но ptr1 не является постоянным указателем.

int const *ptr1=&i, *const ptr2=&j;

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

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

избегайте const_cast как чумы. Есть один или два законных случая использования для него, но их очень мало и далеко между ними. Если вы пытаетесь изменить