Читаем Стандарты программирования на С++ полностью

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

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

{

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

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

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

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

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

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

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

Ссылки

[Dewhurst03] §50 • [Stroustrup94] §11.4.4

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

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

Обсуждение

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

Рассмотрим фрагмент кода, предназначенного для сохранения значения одного типа (char*) и выборки битов этого значения в виде величины иного типа (long):

union {

 long intValue_;

 char* pointerValue_;

};

pointerValue_ = somePointer;

long int gotcha = intValue_;

Здесь есть две проблемы.

• Данный код требует слишком многого. Он полагается на то, что sizeof(long) и sizeof(char*) равны и что их битовые представления идентичны. Эти утверждения справедливы не для всех возможных реализаций (см. рекомендацию 91).

• Он скрывает свое предназначение как от человека, так и от компилятора. Игры с объединениями затрудняют для компилятора поиск ошибок, связанных с типами, а для человека — выявление логических ошибок.

Исключения

Если две POD-структуры являются членами объединения и начинаются с полей одних и тех же типов, можно записывать одно из таких полей, а затем считывать данные из другого.

Ссылки

[Alexandrescu02b] • [Stroustrup00] §C.8.2 • [Sutter04] §36

Перейти на страницу:

Все книги серии C++ In-Depth

Стандарты программирования на С++
Стандарты программирования на С++

Эта книга поможет новичку стать профессионалом, так как в ней представлен сконцентрированный лучший опыт программистов на С++, обобщенный двумя экспертами мирового класса.Начинающий программист найдет в ней простые и понятные рекомендации для ежедневного использования, подкрепленные примерами их конкретного применения на практике.Опытные программисты найдут в ней советы и новые рекомендации, которые можно сразу же принять на вооружение. Программисты-профессионалы могут использовать эту книгу как основу для разработки собственных стандартов кодирования, как для себя лично, так и для группы, которой они руководят.Конечно, книга рассчитана в первую очередь на профессиональных программистов с глубокими знаниями языка, однако она будет полезна любому, кто захочет углубить свои знания в данной области.

Андрей Александреску , Герб Саттер

Программирование, программы, базы данных

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных