|
Программирование >> Перегруженные имена функций и идентификаторы
Мало того, подобные наведенные ошибки вполне могут вести себя по-разному не только на разных тестах, но и на одинаковых. А если еще программа кормится данными, которые поступают непрерывно... и еще она сделана таким образом, что реагирует на события, которые каким-то образом распределяются циклом обработки событий... тогда все будет совсем плохо. Отлаживать подобные программы очень сложно, тем более что зачастую, для того, чтобы получить замеченную ошибку повторно, может потребоваться несколько часов выполнения программы. И что делать в этих случаях? Поиск таких ошибок более всего напоминает шаманские пляски с бубном около костра, не зря этот образ появился в программистском жаргоне. Потому что программист, измученный бдениями, начинает просто случайным образом удалять (закомментировав некоторую область, ии набрав #if 0 ... #endil) блоки своей программы, чтобы посмотреть, в каком случае оно будет работать, а в каком - нет. Это действительно напоминает шаманство, потому что иногда программист уже не верит в то, что, например, от перестановки мест сумма слагаемых не меняется и запросто может попытаться переставить и проверить результат... авось? А вот теперь мы подошли к тому, что в шаманстве тоже можно выделить систему. Для этого достаточно осознать, что большинство загадочных ошибок происходят именно из-за манипуляций с указателями. Поэтому, вместо того чтобы переставлять местами строчки программы, можно просто попытаться для начала закомментировать в некоторых особенно опасных местах удаление выделенной памяти и посмотреть что получится. Кстати сказать, отладка таких моментов требует (именно требует) наличия отладочной информации во всех используемых библиотеках, так будет легче работать. Так что, если есть возможность скомпилировать библиотеку с отладочной информацией, то так и надо делать - от лишнего можно будет избавиться потом. Если загадки остались, то надо двинуться дальше и проверить индексацию массивов на корректность. В идеале, перед каждым обращением к массиву должна находиться проверка инварианта относительно того, что индекс находиться в допустимых пределах. Такие проверки надо делать отключаемыми при помощи макросов DEBUG/RELEASE с тем, чтобы в окончательной версии эти дополнительные проверки не мешались бы (этим, в конце-концов, Си отличается от Java: хотим - проверяем, не хотим - не проверяем). В этом случае вы значительно быстрее сможете найти глупую ошибку (а ошибки вообще не бывают умными; но найденные - глупее оставшихся)). На самом деле, в C++ очень удобно использовать для подобных проверок шаблонные типы данных. То есть, сделать тип массив , в котором переопределить необходимые операции, снабдив каждую из них нужными проверками. Операции необходимо реализовать как inline, это позволит не потерять эффективность работы программы. В то же самое время, очень легко будет удалить все отладочные проверки или вставить новые. В общем, реализация своего собственного типа данных Buffer является очень полезной. Кстати, раз уж зашла об этом речь, то абзац выше является еще одним свидетельством того, что C++ надо использовать полностью и никогда не писать на нем как на усовершенствованном Си . Если вы предпочитаете писать на Си, то именно его и надо использовать. При помощи C++ те же задачи решаются совсем по другому. Создание графиков с помощью ploticus Есть такая программа, предназначенная для создания графиков различных видов из командной строки, называется ploticus. Программа сама по себе достаточно удобная - потому что иногда очень полезно автоматизировать генерацию различных графических отчетов, а тут без командной строки и вызова программ из скриптов не обойтись. Нет, таких программ великое множество, но ploticus отличается от них очень удобным преимуществом: он глупый . То есть, его можно, например, заставить разместить надпись на рисунке с точностью до пиксела... иногда это нужно. Но разговор не об удобстве этой программы. Просто иногда требуется использовать ploticus, но при этом немного доработанный напильником. Сначала немного лирики. Ploticus, для того, чтобы построить график, читает некоторый файл, в котором находится определение этого самого графика (скрипт, так сказать). Этот файл обладает очень простой грамматикой. Мало того, ploticus умеет организовывать программный канал (хотя, кто этого не умеет?) и читать данные оттуда, как результат выполнения другой программы. Так вот о чтении этого файла мы и хотим немного рассказать. Итак, подпрограммы чтения данных в ploticus разбиты на некоторые логические блоки, исходя из структуры самого файла с данными. Ну это понятно и логично. Не особенно понятно другое: каждая подпрограмма (парсер) на вход воспринимает название файла, в котором находится содержимое. В итоге, основная подпрограмма сначала разбивает файл на блоки, содержимое этих файлов копирует (!) во временные файлы (!!), которые подсовывает на вход другим подпрограммам. Это, конечно, уже достаточно оригинально, хотя задумка автора ясна - он хотел сделать так, чтобы в этих местах на вход подпрограммам чтения данных можно было бы подсунуть имя программы, которая эти данные бы сгенерировала. Тем не менее, можно было бы сделать значительно красивее, чем создавать кучу временных текстовых файлов. Эти подпарсеры реализованы... аналогичным образом. Т.е., автор не смущаясь разбивает подсунутые файы еще на кусочки и записывает их в другие временные файлы, которые потом читает. В принципе, все эти места как раз и требовали вмешательства напильника, потому что хотелось иметь программный интерфейс ко всему этому хозяйству и, желательно, чтобы данные не покидали оперативной памяти. Все написанное выше уже смешно. Но кусочек кода, который приведен, может довести программиста до истерического смеха. Вот он (с купюрами): к
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |