Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Саттер Герб. Стандарты программирования на С++. 101 правило и рекомендация - royallib.ru.doc
Скачиваний:
58
Добавлен:
11.03.2016
Размер:
715.24 Кб
Скачать

96. Не применяйте memcpy или memcmp к не-pod типам Резюме

Не работайте рентгеновским аппаратом (см. рекомендацию 91). Не используйте memcpy и memcmp для копирования или сравнения чего-либо структурированного более, чем обычная память.

Обсуждение

Функции memcpy и memcmp нарушают систему типов. Использовать memcpy для копирования объектов — это то же, что использовать ксерокс для копирования денег, а сравнивать объекты при помощи memcmp — то же, что сравнивать двух леопардов по количеству пятен. Инструменты и методы могут казаться подходящими для выполнения работы, но они слишком грубы для того, чтобы сделать ее правильно.

Объекты С++ предназначены для сокрытия данных (возможно, наиболее важный принцип в разработке программного обеспечения; см. рекомендацию 11). Объекты скрывают данные (см. рекомендацию 41) и предоставляют точные абстракции для копирования этих данных посредством конструкторов и операторов присваивания (см. рекомендации с 52 по 55). Пройтись по ним грубым инструментом типа memcpy — серьезное нарушение принципа сокрытия информации, которое зачастую приводит к утечкам памяти и ресурсов (в лучшем случае), аварийному завершению программы (в случае похуже) или неопределенному поведению (в самом худшем случае). Например:

{

 // Создаем два int в памяти

 shared_ptr<int> p1(new int), p2(new int);

 memcpy(&p1, &p2, sizeof(p1)); // Так делать нельзя!!!

} // Утечка памяти: p2 никогда не удаляется

  // повреждение памяти: p1 удаляется дважды

Неверное применение memcpy может влиять на такие фундаментальные свойства, как тип и сущность объекта. Компиляторы часто добавляют к полиморфным объектам скрытые данные (так называемый указатель на виртуальную таблицу), которые определяют сущность объекта во время выполнения программы. В случае множественного наследования в объекте содержится несколько таких таблиц, с различными смещениями внутри объекта, и большинство реализаций добавляют дополнительные внутренние указатели при виртуальном наследовании. При обычном использовании компилятор принимает меры для корректного управления всеми скрытыми полями; применение memcpy способно внести в этот механизм только хаос.

Аналогично, функция memcmp — неподходящий инструмент для сравнения чего-то более сложного, чем просто наборы битов. Иногда эта функция делает слишком мало (например, сравнение строк в стиле С — не то же, что и сравнение указателей, при помощи которых эти строки реализованы). А иногда, как это ни парадоксально, memcmp делает слишком много (например, memcmp может совершенно напрасно сравнивать байты, которые не являются частью состояния объекта, такие как заполнители, вставленные компилятором для выравнивания). В обоих случаях результат сравнения оказывается неверным.

Ссылки

[Dewhurst03] §50 • [Stroustrup94] §11.4.4

97. Не используйте объединения для преобразований Резюме

Хитрость все равно остается ложью: объединения можно использовать для получения "преобразования типа без преобразования", записывая информацию в один член и считывая из другого. Однако это еще более опасно и менее предсказуемо, чем применение reinterpret_cast (см. рекомендацию 92).