Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

• Вставьте инструкции для проверки инвариантов (т.е. условий, которые всегда должны выполняться; см. раздел 9.4.3) в подозрительные разделы.

Рассмотрим пример.

int my_complicated_function(int a, int b, int c)

// Аргументы являются положительными и a < b < c

{

  if (!(0

    error("Неверные аргументы функции mcf");

  // ...

}

• Если все сказанное не привело к успеху, вставьте инварианты в разделы программы, которые вы считаете правильными. Весьма вероятно, что вы найдете ошибку. Инструкция для проверки инвариантов называется assert.

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

<p id="AutBody_Root083"><strong>5.10. Пред- и постусловия</strong></p>

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

int my_complicated_function(int a, int b, int c)

// Аргументы являются положительными и a < b < c

{

  if (!(0

    error("Неверные аргументы функции mcf");

  // ...

}

Во-первых, в комментарии утверждается, какие аргументы ожидает функция, а затем происходит проверка этого условия (и генерирование исключения, если это условие нарушается). Это правильная стратегия. Требования, которые функция предъявляет к своим аргументам, часто называют предусловиями (pre-condition): они должны выполняться, чтобы функция работала правильно. Вопрос заключается в том, что делать, если предусловия нарушаются. У нас есть две возможности.

1. Игнорировать это (надеясь или предполагая, что все вызывающие функции передают правильные аргументы).

2. Проверить их (и каким-то образом сообщить об ошибке).

С этой точки зрения типы аргументов — это лишь способ проверки простейших предусловий на этапе компиляции. Рассмотрим пример.

int x = my_complicated_function(1, 2, "horsefeathers");

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

  Мы предполагаем, что предусловия всегда зафиксированы в комментариях (так что программист, вызывающий функцию, может видеть, что ожидает вызываемая функция). Если функция не содержит комментарии, в которых указаны условия, накладываемые на аргументы, будем считать, что он может принимать любые аргументы. Но стоит ли надеяться, что программист, вызывающий функцию, станет читать эти аргументы и придерживаться установленных правил? Иногда это можно делать, но, как правило, все же следует проверить выполнение предусловий. Это следует делать всегда, если нет веской причины этого не делать. К таким причинам относятся следующие.

• Никто не может передать неправильные аргументы.

• Проверка слишком сильно замедлит выполнение программы.

• Проверка является слишком сложной.

Первую причину можно признать уважительной, только если вы знаете, кто будет вызывать вашу функцию. В реальном мире это практически невозможно.

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

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

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

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

Programming with POSIX® Threads
Programming with POSIX® Threads

With this practical book, you will attain a solid understanding of threads and will discover how to put this powerful mode of programming to work in real-world applications. The primary advantage of threaded programming is that it enables your applications to accomplish more than one task at the same time by using the number-crunching power of multiprocessor parallelism and by automatically exploiting I/O concurrency in your code, even on a single processor machine. The result: applications that are faster, more responsive to users, and often easier to maintain. Threaded programming is particularly well suited to network programming where it helps alleviate the bottleneck of slow network I/O. This book offers an in-depth description of the IEEE operating system interface standard, POSIX (Portable Operating System Interface) threads, commonly called Pthreads. Written for experienced C programmers, but assuming no previous knowledge of threads, the book explains basic concepts such as asynchronous programming, the lifecycle of a thread, and synchronization. You then move to more advanced topics such as attributes objects, thread-specific data, and realtime scheduling. An entire chapter is devoted to "real code," with a look at barriers, read/write locks, the work queue manager, and how to utilize existing libraries. In addition, the book tackles one of the thorniest problems faced by thread programmers-debugging-with valuable suggestions on how to avoid code errors and performance problems from the outset. Numerous annotated examples are used to illustrate real-world concepts. A Pthreads mini-reference and a look at future standardization are also included.

David Butenhof

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