(Копия
блога на Технотреке)
Summary
Мы рассмотрели простейшую структуру данных - стек (буфер LIFO) и его реализацию в Си с точки зрения объектно-ориентированного программирования. Для этого мы применили логическую группировку данных (структуру, struct) и семейство функций (методов), связанных с ней. Типичными методами являются инициализация (конструкция, Stack_ctor), деинициализация (деструкция, или очистка, Stack_dtor), тихая верификация (Stack_OK) и отладочный дамп (Stack_dump). Первые две последних функции поддерживаются С++ как конструкторы и деструкторы; для последних двух нет явно поддерживаемых эквивалентов, но без них легко допустить ошибку даже в простой структуре данных и очень тяжело ее поймать. Также рассмотрели стратегии двойной проверки для динамической верификации объектов стека.
Домашнее задание
1. Реализуйте стек с внешним хранением данных в динамической памяти (более простой вариант задания - с внутренним хранением данных в самой структуре стека), его Си-эквиваленты конструктора, деструктора, тихого верификатора и дампа. Сделайте очень подробный и красивый дамп! (
См. пример дампа здесь, на заднем плане.) Подумайте, как дамп может выводить имя переменной стека (в отладочном режиме компиляции).
2. Прочитайте, что такое юнит-тесты (готовьте вопросы к след. лекции) и реализуйте их для стека в достаточном количестве.
3. Попробуйте запортить стек, сделав намеренные ошибки в методах push() и рор(): переполнение и антипереполнение стека, смена знака счетчика стека, обнуление указателя на данные и т.п. Все ли эти ошибки являются критическими, говорящими об испорченных данных, или некоторые из них являются лишь некорректными действиями, примененными к правильно устроенному стеку? Разработайте стратегии реакции на разные виды ошибок в режимах компиляции Debug и Release (кстати, что что такое? См. про условную компиляцию), прочитайте про errno. Жду Ваших вопросов и обсуждения по этой задаче.
4. Попробуйте запортить стек внешним образом, за пределами его методов. Например, объявите до и после стековой переменной по массиву и позаходите за их границы, залезая в структуру стека и перезаписывая ее содержимое. (Обычно компилятор располагает переменные в памяти по порядку их объявления.) Как в этом случае детектировать такие ошибки и реагировать на них?
5*. Реализуйте юнит-тесты, намеренно создающие ошибочные ситуации и проверяющие реакцию системы верификации - это юнит-тесты к самим верификаторам.
На следующей лекции мы обсудим Ваши инженерные решения (готовьтесь! советую пообсуждать это друг с другом; в идеале часть лекции можно посвятить коротким выступлениям команд или менторских групп).
***
По фидбеку, есть те, кому лекция слишком очевидна - это нормально, у всех разная подготовка. Подойдите ко мне после лекции, мы подумаем, как с вами работать в более быстром режиме, чтобы вам было более интересно.
Удачи, и May the Source be with you! :)