как все мы знаем, использование const_cast для удаления константности указателя следует избегать.
Но как обстоят дела с этим?
Для моего случая использования у меня есть функция, которая копирует данные (байты) из неконстантного исходного буфера.
Я подумал, что хорошее дизайнерское решение — объявить параметр в соответствии с исходным буфером полностью постоянным.
void copyfunction(const char* const data) { ... }
Для вызова функции, как показано ниже, это приведет к ошибке типа указателя ‘const char * const <-> char * ‘.
void main() {
char sourcebuffer[] = {0x00};
copyfunction(sourcebuffer);
}
Конечно, теперь я мог бы просто объявить sourcebuffer
как const, но в моем случае у меня нет доступа к этой переменной, потому что она находится в другом месте кода (внешняя библиотека).
void main() {
char sourcebuffer[] = {0x00};
copyfunction(const_cast<const char* const>(sourcebuffer));
}
Тем не менее, код за его пределами будет работать, но это хороший стиль (в соответствии с моим вариантом использования)?
Я думал, объявив параметр copyfunction
as const гарантирует пользователю не изменять (только для чтения) указатель или местоположение самого исходного буфера.
Таким образом, в этом случае const_cast будет только необходимым злом, чтобы позволить вызов функции, а не преднамеренно удалять постоянство указателя …
поздравил
Вы не должны использовать const_cast
добавить const
, так как:
это не нужно T*
неявно преобразуется в const T*
, Ваш вопрос гласит, что char sourcebuffer[] = {0x00}; copyfunction(sourcebuffer);
это ошибка, но это не так.
это потенциально (хотя и маловероятно) вредно. Может удалить volatile
от типа указателя, который здесь не является намерением и приведет к неопределенному поведению, если sourcebuffer
были объявлены как volatile sourcebuffer[]
,
Вы не должны использовать const_cast
добавить const
так как
В случаях, когда операция безопасна, это почти всегда не требуется. int*
превращается в const int*
неявно.
Он может делать что-то, чего вы не хотите. Может раздеться volatile
или заставит вас упустить тот факт, что const
был добавлен где-то еще в ваших переменных и ваших const_cast
теперь молча их раздевает.
В тех случаях, когда требуется добавить const
Его использование опасно в рассуждениях.
Есть случаи, когда нужно позвонить const_cast
чтобы добавить const
это не произойдет неявно.
void assign_ptr( int const*& lhs, int const* rhs ) { lhs = rhs; }
int const foo = 7;
int* bar = nullptr;
assign_ptr( const_cast<int const*&>(bar), &foo );
*bar = 2; // undefined behavior!
std::cout << foo << "@" << &foo << "\n"; // will print probably 7@something
std::cout << *bar << "@" << bar << "\n"; // will print probably 2@same address as above!
вышеуказанный призыв к assign_ptr
только добавляет const
, но это не произойдет неявно.
Побочным эффектом является то, что модификация *bar
является неопределенным поведением, так как оно изменяет объявленную переменную const
(это делает bar
, int*
, указывать на foo
const int
).
Так что пока const_cast
требуется сделать assign_ptr
вызов компиляции, потому что это было небезопасно. const_cast
не делает его более безопасным, он просто скрывает ошибку.
Это частный случай проблемы прямоугольника. Квадраты не являются прямоугольниками, потому что если вы измените ширину квадрата, его высота также изменится, и этого не произойдет, если вы измените прямоугольник. Так же, int**
не int const**
, (Обратите внимание, что неизменяемые квадраты являются своего рода неизменяемым прямоугольником; именно мутация вызывает проблему. В случае указателей int*const*
это int const*const*
: изменчивость указателей «более высокого уровня» вызывает проблему.)