Ответ 1
const int *var;
const
- контракт. Получив параметр const int *
, вы "сообщите" вызывающему, что вы (вызываемая функция) не будете изменять объекты, на которые указывает указатель.
В вашем втором примере явно разрывает этот контракт, отбрасывая квалификатор const и затем изменяя объект, на который указывает полученный указатель. Никогда не делайте этого.
Этот "контракт" применяется компилятором. *dummy = 1
не будет компилироваться. Бросок - это способ обойти это, сообщая компилятору, что вы действительно знаете, что делаете, и позволяете вам это делать. К сожалению, "я действительно знаю, что делаю", обычно не так.
const
также может использоваться компилятором для выполнения оптимизации, иначе он не мог бы.
Undefined Поведение:
Обратите внимание, что в то время как сам листинг является технически законным, изменение значения, объявленного как const
, - это Undefined Поведение. Так что технически исходная функция в порядке, если переданный ей указатель указывает на данные, объявленные изменчивыми. Иначе это Undefined Поведение.
подробнее об этом в конце сообщения
Что касается мотивации и использования, давайте возьмем аргументы функций strcpy
и memcpy
:
char* strcpy( char* dest, const char* src );
void* memcpy( void* dest, const void* src, std::size_t count );
strcpy
работает с строками char, memcpy
работает с общими данными. Хотя я использую пример strcpy, следующее обсуждение для обоих одинаково, но с char *
и const char *
для strcpy
и void *
и const void *
для memcpy
:
dest
есть char *
, потому что в буфере dest
функция поместит копию. Функция будет изменять содержимое этого буфера, поэтому оно не является константой.
src
const char *
, потому что функция только считывает содержимое буфера src
. Он не меняет его.
Только взглянув на объявление функции, вызывающий может утверждать все вышеперечисленное. По контракту strcpy
не будет изменять содержимое второго буфера, переданного в качестве аргумента.
const
и void
являются ортогональными. Это все обсуждение выше о const
применяется к любому типу (int
, char
, void
,...)
void *
используется в C для "общих" данных.
Еще больше на Undefined Поведение:
Случай 1:
int a = 24;
const int *cp_a = &a; // mutabale to const is perfectly legal. This is in effect
// a constant view (reference) into a mutable object
*(int *)cp_a = 10; // Legal, because the object referenced (a)
// is declared as mutable
Случай 2:
const int cb = 42;
const int *cp_cb = &cb;
*(int *)cp_cb = 10; // Undefined Behavior.
// the write into a const object (cb here) is illegal.
Я начал с этих примеров, потому что их легче понять. Отсюда есть только один шаг для использования аргументов:
void foo(const int *cp) {
*(int *)cp = 10; // Legal in case 1. Undefined Behavior in case 2
}
Случай 1:
int a = 0;
foo(&a); // the write inside foo is legal
Случай 2:
int const b = 0;
foo(&b); // the write inside foo causes Undefined Behavior
Снова я должен подчеркнуть: если вы действительно не знаете, что делаете, и все люди, работающие в настоящем и будущем в коде, являются экспертами и понимают это, и у вас есть хорошая мотивация, если все вышеперечисленные встретил, никогда не отбрасывал константу!!