Правила программирования на С и С++. Главы 1-6 - Немедленно обрабатывайте особые случаи
ОГЛАВЛЕНИЕ
Страница 78 из 93
71. Немедленно обрабатывайте особые случаи.
Пишите свои алгоритмы таким образом, чтобы они обрабатывали вырожденные случаи немедленно. Вот тривиальный пример того, как сделать это неправильно:
print( const char *str ){
if ( !*str ) // ничего не делать, строка пуста return;while ( *str ) putchar( *str++ );}Оператор if тут не нужен, потому что этот случай хорошо обрабатывается циклом while.Листинги 2 и 3 демонстрируют более реалистический сценарий. Листинг 2 определяет умышленно наивный заголовок связанного списка и функцию для удаления из него элемента.
Листинг 2. Связанный список: Вариант 1.
- typedef struct node
- {
- struct node *next, *prev;
- //...
- } node;
- node *head;
- remove( node **headp, node *remove )
- {
- // Удалить элемент, на который указывает "remove", из списка, на начало
- // которого указывает *headp.
- if ( *headp == remove ) // Этот элемент в начале списка.
- {
- if ( remove->next ) // Если это не единственный элемент в списке,
- remove->next->prev = NULL; // то поместите следующий за ним элемент
- // первым в списке.
- *headp = remove->next;
- }
- else // Элемент находится в середине списка
- {
- remove->prev->next = remove->next;
- if ( remove->next )
- remove->next->prev = remove->prev;
- }
- }
Смысл этого состоит в том, что незначительная переделка этой задачи позволяет мне использовать алгоритм, не имеющий особых случаев, этим самым упрощая программу. Конечно, эта простота не дается бесплатно - теперь стало невозможным перемещение по списку в обратном направлении - но нам ведь это может быть и не нужно.
Листинг 3. Связанный список: Вариант 2.
- typedef struct node
- {
- struct node *next, **prev; // ?=== К prev добавлен символ *
- // ...
- } node;
- node *head;
- remove( node **headp, node *remove )
- {
- if ( *(remove->prev) = remove->next ) // если не в конце списка,
- remove->next->prev = remove->prev; // то уточнить следующий элемент
- }