Совершенно разумно привести void *
к const void *
, и компилятор должен делать это неявно за кулисами, не думая с вашей стороны, но обратный путь опасен и его следует избегать.
Помните, что если функция принимает указатель const
, вы можете передать ей либо значение const
, либо не const
.То, что вы берете указатель const
, означает, что ваша функция не изменяет память.
Пример: (обратите внимание, что строки, помеченные ОПАСНОСТЬ должны выдавать ошибку компилятора)
const void *p_const;
void *p_buffer;
// const pointers are allowed to hold static memory
p_const = "Foo"; // allowed
p_buffer = "Foo"; // DANGER!!!
// casting to const is implicit
p_const = malloc(LEN); // allowed - implicit cast
p_buffer = malloc(LEN); // allowed
// casting to const implicit again
write(STDOUT, p_const, LEN); // allowed
write(STDOUT, p_buffer, LEN); // also allowed - implicit cast
// const memory cannot be used where mutable memory is expected
read(0, p_buffer, LEN); // allowed
read(0, p_const, LEN); // DANGER!!
// To make the above more obivous, we'll skip the intermediate variable
// and place instead what it holds
read(0, malloc(LEN), LEN); // allowed - useless but at least no crashes
read(0, "foo", 4); // DANGER!!!
Как правило, если записываемая вами функция принимаетуказатель на значение, которое вы не собираетесь изменять, тогда сигнатура функции должна использовать указатель const
.Использование указателя, который не объявлен const
, означает, что память, на которую вы указываете, может быть изменена.
Другой пример:
void do_something(const void* ptr, int length);
// Since the signature is a const pointer, I know I can call it like this:
do_something("foo",4);
И наоборот, вызовы функций длянепостоянный указатель, тогда я должен допустить его:
void do_something(void* ptr, int length);
// This tells me that the function may overwrite my value.
// The safe solution therefore looks more like this:
char *myptr = char[4];
memcpy(myptr,"foo",4);
do_something(myptr,4);
Точно так же, если вы когда-нибудь окажетесь в ситуации, когда вам нужно привести const
указатель к не- const
Вы должны продублировать указанное значение в изменяемой части памяти и передать свой дубликат функции, а не оригиналу.Если это звучит как головная боль, это потому, что это так.Если вы оказались в такой ситуации, значит, вы, вероятно, сделали что-то не так.
Концептуально, если переменная содержит «значение», то это, вероятно, указатель const
.Если вместо этого он содержит «буфер», то это указатель не const
.
Указатели в сигнатурах вашей функции должны всегда быть объявленными const
, если вы не собираетесь писать вэта память.Следование этому правилу поможет вам избежать катастрофических проблем в логике вашей программы.
Я не понимал это простое правило, пока не программировал 6 лет.