83. Используйте отладочную реализацию STL
83. Используйте отладочную реализацию STL
Резюме
Безопасность превыше всего (см. рекомендацию 6). Используйте отладочную реализацию STL[4], даже если она имеется только для одного из ваших компиляторов, и даже если она используется только для отладочного тестирования.
Обсуждение
Так же, как легко ошибиться при работе с указателями, легко допустить и ошибку при работе с итераторами, причем такую, что программа при этом успешно компилируется, а при работе немедленно аварийно завершается (в лучшем случае) или работает неверно (в худшем). Даже если ваш компилятор не обнаружил ни одной ошибки, вы не должны полагаться на "визуальный контроль": имеются специальные инструменты — воспользуйтесь ими.
Ряд ошибок при работе с STL часто допускают даже опытные программисты.
• Использование недействительных или неинициализированных итераторов. В особенности легко допустить первое.
• Передача индекса, выходящего за границы контейнера. Например, обращение к 113-му элементу 100-элементного контейнера.
• Использование "диапазона" итераторов, который на самом деле не является диапазоном. Например, передача двух итераторов, первый из которых не предшествует второму, или когда они указывают на разные контейнеры.
• Передача неверной позиции итератора. Вызов функции-члена контейнера, которая получает позицию итератора (как, например, позиция, передаваемая функции insert), но с передачей итератора, который указывает в другой контейнер.
• Использование неверного упорядочения. Предоставление неверного правила для упорядочения ассоциативного контейнера или в качестве критерия сравнения в алгоритме сортировки (см. примеры в [Meyers01]). Если не использовать отладочной версии STL, такие ошибки обычно проявляются в процессе выполнения программы как неверное поведение или бесконечные циклы, но не как аварийный останов.
Большинство отладочных реализаций STL автоматически обнаруживают такие ошибки, при помощи дополнительной отладочной и системной информации, хранящейся в контейнерах и итераторах. Например, итератор может запомнить контейнер, к которому он обращается, а контейнер — запомнить все итераторы, ссылающиеся на него, так что можно отследить использование ставшего недействительным итератора. Конечно, это увеличивает размер итераторов и контейнеров, а также требует выполнения дополнительных действий при каждом изменении контейнера. Но возможность отслеживания ошибок стоит того — по крайней мере, в процессе отладки, а возможно, и в окончательной версии программы (вспомните рекомендацию 8; не отключайте полезные проверки для повышения производительности до тех пор, пока не убедитесь в необходимости такого шага непосредственными измерениями).
Даже если вы не намерены оставлять проверки в окончательной версии, и даже если у вас имеется проверочная реализация STL только для одной из используемых вами платформ, обязательно протестируйте вашу программу полным комплектом тестов с использованием отладочной реализации STL. Вы не пожалеете об этом.
Примеры
Пример 1. Использование недействительного итератора. Очень просто забыть, что итераторы стали недействительны, и воспользоваться таким недействительным итератором (см. рекомендацию 99). Рассмотрим подобный пример, адаптированный из [Meyers01], где происходит вставка элементов в начало deque:
deque<double>::iterator current = d.begin();
for (size_t i =0; i < max; ++i )
d.insert(current++, data[i] + 41); // Видите ли вы ошибку?
Быстро ответьте — увидели ли вы ошибку в приведенном фрагменте или нет? У вас только три секунды!
Время вышло! Если вы не заметили ошибку за отпущенное время, не волнуйтесь — это достаточно тонкая и понятная ошибка. Отладочная версия STL обнаружит данную ошибку на второй итерации цикла, так что вам не придется полагаться на свой невооруженный взгляд. (Исправленная версия данного кода и альтернативные варианты вы найдете в рекомендации 84.)
Пример 2. Использование диапазона итераторов, на самом деле не являющегося диапазоном. Диапазон итераторов представляет собой пару итераторов first и last, которые указывают на первый элемент диапазона, и элемент, следующий за последним элементом диапазона. Диапазон требует, чтобы итератор last был достижим из first путем некоторого количества повторных увеличений при помощи оператора инкремента итератора first. Известны два распространенных вида ошибки, когда происходит попытка использовать диапазон, который на самом деле диапазоном не является. Первая ошибка возникает, когда два итератора ограничивают диапазон в пределах одного контейнера, но итератор first на самом деле не предшествует итератору second:
for_each(c.end(),с.begin(),Something); // не всегда очевидно
На каждой итерации своего внутреннего цикла алгоритм for_each будет проверять итератор first на равенство итератору second, и до тех пор, пока они не равны, он будет увеличивать итератор first. Конечно, сколько бы раз не был увеличен итератор first, ему никогда не стать равным итератору second, так что цикл по сути оказывается бесконечным. На практике в лучшем случае цикл завершится выходом за пределы контейнера с и немедленным аварийным завершением программы из-за нарушения защиты памяти. В худшем случае, выйдя за пределы контейнера, итератор будет считывать или даже менять данные, не являющиеся частью контейнера. Этот результат в принципе не слишком отличается от знакомых нам последствий переполнения буфера…
Вторая распространенная ошибка возникает, когда итераторы указывают в разные контейнеры:
for_each(c.begin(),d.end(),Something); // не всегда очевидно
Результат такой ошибки аналогичен результату предыдущей. Однако поскольку итераторы отладочной версии STL помнят контейнер, с которым работают, такую ошибку можно выявить во время выполнения программы.
Ссылки
[Dinkumware-Safe] • [Horstmann95] • [Josuttis99] §5.11.1 • [Metrowerks] • [Meyers01] §21, §50 • [STLport-Debug] • [Stroustrup00] §18.3.1, §19.3.1
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Используйте с умом
Используйте с умом Как и все блестящие новые инструменты, переходы стоит использовать там, где они уместны. Очень легко нарушить чувство меры и добавить переходы ко всем элементам на странице, таким образом превратив ее в раздражающего пульсирующего монстра. Очень
Еще раз: используйте с умом
Еще раз: используйте с умом Потратив немного времени на размышления о смысле содержимого, с которым мы работаем, мы можем выбрать некоторые свойства CSS3, которые функционируют сегодня, вместе с переходами и преобразованиями.Такие улучшения взаимодействия могут быть
8.5. Используйте WPA или WPA2
8.5. Используйте WPA или WPA2 Протоколы WPA (Wi-Fi Protected Access), WPA2 и WEP (Wired Equivalent Privacy) обеспечивают защиту и шифрование данных, передаваемых беспроводным маршрутизатором и беспроводным клиентом. Предпочтительнее использовать WPA2, но если этот протокол устройством не поддерживается,
1.7. Максимально используйте бенчмаркинг
1.7. Максимально используйте бенчмаркинг Отрасль веб-разработок – это одна из самых открытых для копирования передового опыта, бенчмаркинга, сфера бизнеса. Скорость распространения и клонирования инноваций здесь может измеряться часами.Постоянно изучайте не только
Используйте привычные для клиентов слова
Используйте привычные для клиентов слова Давайте посмотрим, какие слова можно задействовать для описания ваших товаров или вашей компании. В частности, требуется подобрать такие, которые используют ваши посетители. Вы удивитесь, но они порой называют вещи совсем
Используйте отступы!
Используйте отступы! Правильное использование отступов служит основой создания понятного программного кода. В примере из предыдущего раздела каждая пара операторов, определяющих одну структуру, напечатана с одним и тем же отступом. При наличии отступов проще выяснить,
3. Используйте систему контроля версий
3. Используйте систему контроля версий РезюмеКак гласит китайская пословица, плохие чернила лучше хорошей памяти: используйте системы управления версиями. Не оставляйте файлы без присмотра на долгий срок. Проверяйте их всякий раз после того, как обновленные модули
15. Активно используйте const
15. Активно используйте const Резюмеconst — ваш друг: неизменяемые значения проще понимать, отслеживать и мотивировать, т.е. там, где это целесообразно, лучше использовать константы вместо переменных. Сделайте const описанием по умолчанию при определении значения — это
95. Не используйте преобразование типов в стиле С
95. Не используйте преобразование типов в стиле С РезюмеВозраст не всегда означает мудрость. Старое преобразование типов в стиле С имеет различную (и часто опасную) семантику в зависимости от контекста, спрятанную за единым синтаксисом. Замена преобразования типов в
97. Не используйте объединения для преобразований
97. Не используйте объединения для преобразований РезюмеХитрость все равно остается ложью: объединения можно использовать для получения "преобразования типа без преобразования", записывая информацию в один член и считывая из другого. Однако это еще более опасно и менее
98. Не используйте неизвестные аргументы (троеточия)
98. Не используйте неизвестные аргументы (троеточия) РезюмеНаличие троеточий в С++ — опасное наследие С. Избегайте их в своих программах; используйте вместо этого высокоуровневые конструкции и библиотеки С++.ОбсуждениеФункции с переменным количеством аргументов
19.2.3.2. Используйте автоинструменты GNU
19.2.3.2. Используйте автоинструменты GNU Определение конфигурационных параметров должно быть выполнено во время компиляции. Значительное преимущество дистрибутивов с открытым исходным кодом заключается в том, что они позволяют адаптировать пакет к обнаруженной среде на
19.2.3.2. Используйте автоинструменты GNU
19.2.3.2. Используйте автоинструменты GNU Определение конфигурационных параметров должно быть выполнено во время компиляции. Значительное преимущество дистрибутивов с открытым исходным кодом заключается в том, что они позволяют адаптировать пакет к обнаруженной среде на
Ошибка 0x00000074: используйте F8
Ошибка 0x00000074: используйте F8 Решить проблему можно, загрузившись в последней удачной конфигурации. Для этого перед загрузкой Windows нажмите F8, а затем выберите Загрузка последней удачной конфигурации (см. рис. 10.3, гл.