}
Эта пара функций (по одной для указателей и ссылок) просто проверяет согласованность двух вариантов преобразования. Вы можете либо самостоятельно приспособить checked_cast
94. Избегайте преобразований, отменяющих const
Преобразование типов, отменяющее const
Применение const
const для объекта, который изначально был объявлен как константный, задний ход приводит вас на территорию неопределенного поведения. Например, компилятор может (и, бывает, так и поступает) поместить константные данные в память только для чтения (ROM) или в страницы памяти, защищенные от записи. Отказ от const у такого истинно константного объекта — преступный обман, зачастую караемый аварийным завершением программы из-за нарушения защиты памяти.Даже если ваша программа не потерпит крах, отмена const
void Foolish(unsigned int n) {
const unsigned int size = 1;
const_cast
char buffer[size]; // Размер массива
// ... // все равно равен 1
}
В С++ имеется одно неявное преобразование const_cast
char*:char* weird = "Trick or treat?";
Компилятор молча выполняет преобразование const_cast
const char[16] в char*. Это преобразование позволено для совместимости с API в стиле С, хотя и представляет собой дыру в системе типов С++. Строковые литералы могут размещаться в памяти только для чтения, и попытка изменения такой строки может вызвать нарушение защиты памяти.Преобразование, отменяющее const
const Object& f(const Object&);
Object& f(Object& obj {
const Object& ref = obj;
return const_cast
} // возвращаемого типа
95. Не используйте преобразование типов в стиле С
Возраст не всегда означает мудрость. Старое преобразование типов в стиле С имеет различную (и часто опасную) семантику в зависимости от контекста, спрятанную за единым синтаксисом. Замена преобразования типов в стиле С преобразованиями С++ поможет защититься от неожиданных ошибок.
Одна из проблем, связанных с преобразованием типов в стиле С, заключается в том, что оно использует один и тот же синтаксис для выполнения несколько разных вещей, в зависимости от таких мелочей, как, например, какие именно заголовочные файлы включены при помощи директивы #include
reinterpret_cast (см. рекомендацию 92).Рассмотрим следующий код, в котором Derived
Base:extern void Fun(Derived*);
void Gun(Base* pb) {
// Будем считать, что функция Gun знает, что pb в
// действительности указывает на объект типа Derived и
// хочет передать его функции Fun
Derived* pd = (Derived*)pb; // Плохо: преобразование
Fun(pd); // в стиле С
}