Читаем Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ полностью

Избегать неоправданных расхождений с поведением встроенных типов необходимо для того, чтобы обеспечить согласованность интерфейсов. Из всех характеристик простых для применения интерфейсов согласованность – наверное, самая важная. И наоборот, несогласованность – прямая дорога к ухудшению качества интерфейса. Интерфейсы STL-контейнеров в большинстве случаев согласованы (хотя и не идеально), и это немало способствует простоте их использования. Например, каждый STL-контейнер имеет функцию-член size, которая сообщает, сколько объектов содержится в контейнере. Напротив, в языке Java для массивов используется свойство length, для класса String – метод length, а для класса List – метод size. Также и в. NET: класс Array имеет свойство Length, а класс ArrayList – свойство Count. Некоторые разработчики считают, что интегрированные среды разработки (IDE) делают эти несоответствия несущественными, но они ошибаются. Несоответствия мешают программисту продуктивно работать, и ни одна IDE это не компенсирует.

Любой интерфейс, который требует, чтобы пользователь что-то помнил, может быть использован неправильно, ибо пользователь вполне способен забыть, что от него требуется. Например, в правиле 13 представлена фабричная функция, которая возвращает указатель на динамически распределенный объект в иерархии Investment:

Investment *createInvestment(); // из правила 13: параметры

// для простоты опущены

Чтобы избежать утечки ресурсов, указатель, возвращенный createInvestment, обязательно должен быть удален. Следовательно, пользователь может совершить, по крайней мере, две ошибки: забыть удалить указатель либо удалить его более одного раза.

Правило 13 показывает, как клиенты могут поместить значение, возвращенное createInvestment, в «интеллектуальный» указатель наподобие auto_ptr или tr1::shared_ptr, возложив тем самым на него ответственность за вызов delete. Но что, если клиент забудет применить «интеллектуальный» указатель? Во многих случаях для предотвращения этой проблемы лучше было бы написать фабричную функцию, которая сама возвращает «интеллектуальный» указатель:

std::tr1::shared_ptr createInvestment();

Тогда пользователь будет вынужден сохранять возвращаемое значение в объекте типа tr1::shared_ptr, и ему не придется помнить о том, что объект Investment по завершении работы с ним необходимо удалить.

Фактически возврат значения типа tr1::shared_ptr позволяет проектировщику интерфейса предотвратить и многие другие ошибки, связанные с освобождением ресурса, потому что, как объяснено в правиле 14, tr1::shared_ptr допускает привязку функции-чистильщика к интеллектуальному указателю при его создании (auto_ptr не имеет такой возможности).

Предположим, что от пользователя, который получил указатель Investment* от createInvestment, ожидается, что в конце работы он передаст его функции getRidOfInvestment, вместо того чтобы применить к нему delete. Подобный интерфейс – прямая дорога к другой ошибке, заключающейся в использовании не того механизма удаления ресурсов (пользователь может все-таки вызвать delete вместо getRidOfInvestment). Реализация createInvestment может снять эту проблему за счет того, что вернет tr1::shared_ptr с привязанной к нему в качестве чистильщика функцией getRidOfInvestment.

Конструктор tr1::shared_ptr принимает два аргумента: указатель, которым нужно управлять, и функцию-чистильщик, которая должна быть вызвана, когда счетчик ссылок достигнет нуля. Это наводит на мысль попытаться следующим образом создать нулевой указатель tr1::shared_ptr с getRidOfInvestment в качестве чистильщика:

std::tr1_shared_ptr // попытка создать нулевой shared_ptr

pInv(0, getRidOfInvestment); // с чистильщиком

// это не скомпилируется

К сожалению, C++ это не приемлет. Конструктор tr1::shared_ptr требует, чтобы его первый параметр был указателем, а 0 – это не указатель, это целое. Да, оно преобразуется в указатель, но для данного случая этого недостаточно: tr1::shared_ptr настаивает на настоящем указателе. Приведение типа решает эту проблему:

std::tr1_shared_ptr // создает null shared_ptr

pInv(static_cast(0), // с getRidOfInvestment в качестве

getRidOfInvestment); // чистильщика. о static_cast см.

// в правиле 27

Это значит, что код, реализующий createInvestment, который должен возвратить tr1::shared_ptr с getRidOfInvestment в качества чистильщика, будет выглядеть примерно так:

std::tr1::shared_ptr createInvestment()

{

std::tr1::shared_ptr retVal(static_cast(0),

getRidOfInvestment);

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

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

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

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

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

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

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

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

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