Программирование >>  Обобщенные обратные вызовы 

1 ... 63 64 65 [ 66 ] 67 68 69 ... 84


> Рекомендация

Последовательно и корректно используйте квалификатор const,

6. Удаление избыточного кода. В программе явным образом определяется конструктор класса sort i dxtbl pai г по умолчанию, хотя он не имеет никаких отличий от неявно генерируемой версии, так что особого смысла в нем нет. Кроме того, поскольку sort i dxbT pai г является структурой с открытыми данными, наличие отдельной операции set, которая вызывается только в одном месте, приводит только к усложнению кода, ничего не давая взамен.

> Рекомендация

Избегайте избыточности и повторения кода.

Теперь перейдем к основной функции sort idxtbT template <class RAlteo

void sort idxtbl ( RAlter fi rst, RAlter last, int* pidxtbl ) int iDst = last-fi rst;

typedef std:: vector< sort idxtbl pai r <RAlter> > V; V v( iDst ); int i=0;

RAlter it = first;

v: literator vit = v.beginC);

for С i=0; it<last; it++, vit++, \++ )

C*vit).setCit,i): std: rsortCv.begin C) , v.endO); int *pi = pidxtbl ; vit = V.beginC);

for С ; vit<v.endC); pi++, vit++ ) *pi = C*vit).i;

7. Используйте значащие и соответствующие по смыслу имена. В данном случае имя sort i dxtbl вводит в заблуждение, поскольку функция не сортирует индексную таблицу, а создает ее! С другой стороны, имя параметра шаблона RAlter выбрано удачно, так как указывает на использование итератора с произвольным доступом (random-access iterator) - именно то, что и требуется в данном исходном тексте, так что такое имя служит хорошим напоминанием.

> Рекомендация

Используйте понятные и выразительные имена.

8. Будьте последовательны. В функции sort i dxtbl переменные иногда инициализируются в инструкции инициализации цикла, а иногда - нет, что затрудняет чтение кода - по крайней мере, для меня.

9. Избавляйтесь от неоправданной сложности. Эта функция просто обожает излишние локальные переменные! Есть три подтверждения этому. Во-первых, переменная iDst, инициализированная значением last-fi rst и использованная только один раз. Почему бы просто не записать в месте се использования разность last-fi rst и избавиться от нее? Во-вторых, итератор вектора vit создается там, где уже имеется и может использоваться индекс (код от этого станет только понятнее). В-третьих, локальная переменная it инициализируется значением параметра функции, который после этого никогда не используется; лично я предпочитаю в такой ситуации воспользоваться параметром функции (даже если вы измените его - ничего страшного!) вместо введения другого имени.



10. Повторное использование, часть 1: интенсивнее используйте стандартную библиотеку. В приведенной программе вполне правильно используется функция std::sort, и это хорошо. Но что такое последний цикл, как не копирование, которое вполне можно выполнить при помоши функции std: :сору? Зачем вводить специальный класс sort idxtbl pai г, если его единственное отличие от std::pai г в наличии функции сравнения? Помимо простоты, повторное использование стандартной библиотеки делает код более удобочитаемым. Будьте скромнее и используйте результаты чужого труда!

> Рекомендация

Следует хорошо знать и использовать в своем коде возможности стандартной библиотеки вместо написания собственного кода.

И. Повторное использование, часть 2: убить двух зайиев. повышая степень повторного использования своего кода. В исходном фрагменте ничто, кроме самой функции, не может быть использовано повторно. В с п ом о гате л ь н ы й класс sort i dxtbl pai г написан сугубо для использования в данной функции и не может быть повторно использован независимо от функции.

12. Повторное использование, часть 3: улучшение сигнатуры. Исходная сигнатура

template <class RAlter>

void sort idxtbl С RAiter first, RAlter last, int* pidxtbl )

получает простой указатель i nt* на выходную область, чего я обычно стараюсь избегать в пользу более управляемого представления (например, vector). В конце концов, пользователь должен иметь возможность вызвать sort idxtbl и поместить выходные данные в обычный массив, вектор или куда-то еше. Требование иметь возможность поместить данные в произвольный контейнер просто кричит о том, что надо воспользоваться итератором, правда? (См. также задачи 5 и 6.)

tempiate< class RAin, class Out >

void sort idxtbl( RAin fi rst, RAin last, Out result )

> Рекомендация

Избегайте жесткого указания типов там, где без этого можно обойтись. Это позволит расширить возможности повторного использования вашего кода.

13. Повторное использование, часть 4. или Сравнивайте итераторы при помощи !=. При сравнении итераторов всегда используйте оператор 1= (который работает для всех типов итераторов) вместо < (который работает только для итераторов с произвольным доступом), конечно, кроме тех случаев, когда вы действительно нуждаетесь в использовании < и будете работать исключительно с итераторами с произвольным доступом. В приведенной программе для сравнения итераторов применен оператор <, что подра зумеваст использование итераторов с произвольным доступом, для которых программа изначально и предназначена: для создания индексов в векторах и массивах (которые оба поддерживают итераторы с произвольным доступом). Но нет причин, по которым мы бы не могли захотеть сделать то же с контейнерами другого вида, например, 1 i st или set (которые не поддерживают итераторы с произвольны.м доступом), и единственная причина, по которой исходная программа не может с ними работать, - это использование оператора < для сравнения итераторов вместо оператора !=.

Вот как по этому поводу пишет Скотт Мейерс в 32 разделе своей книги [Meyers96]: Хорошее программное обеспечение приспособлено к изменениям. Оно в состоянии включать новые возможности, его можно перенести на новые платформы, оно допускает подгонку под новые требования, может работать с новыми входными данными.



Такие гибкие, интеллектуальные и надежные программы не получаются случайно - это результат конструирования и реализации специалистами, которые, помня о нуждах дня сегодняшнего, не забывают о дне завтрашнем и его возможных требованиях к программе. Такие программы, приспособленные к видоизменению, создаются программистами, которые закладывают в свои программы будущее.

> Рекомендация

Предпочтительно сравнивать итераторы при помощи оператора ! =, а не <.

14. Если только вам не требуется прежнее значение итератора, используйте префиксный инкремент (декремент). При работе с итераторами использование префиксной формы инкремента (++i), а не постфиксной (i++) должно стать привычкой; см. [SutterOO] (задача 1.6 русского издания). Конечно, существенного различия в приведенном фрагменте может и не быть, поскольку vector<T>: :iterator может представлять собой простой указатель т* (хотя это может быть и не так), но если мы реализуем пункт 13, то код не будет ограничен использованием одного лишь типа vector<T>: .-iterator, а большинство итераторов других типов представляют собой классы. Возможно, их копирование не требует много процессорного времени - но зачем напрасно допускать даже такое малое снижение производительности программы?

> Рекомендация

Если только вам не требуется прежнее значение итератора, используйте префиксный инкремент.

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

Я сознательно не рассматривал стиль написания данного фрагмента, поскольку, в конце концов, его основным предназначением была всего лишь демонстрация читателям журнальной статьи принципа работы игщексных таблиц.

Резюме

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

Улучшенная версия кода из [HicksOO].

#inciude <vector>

#include <map>

#include <algorithm>

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



1 ... 63 64 65 [ 66 ] 67 68 69 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика