Українська
Текстовий формат і пам’ять
Проєктування текстового формату
Нехай один рядок містить name;score. Перш ніж писати find(';'), потрібно визначити, чи може ім’я бути порожнім, містити крапку з комою або початкові пробіли. Для простої навчальної моделі можна вимагати непорожнє ASCII-ім’я без розділювача та цілий бал 0–100. Тоді рядок повинен мати рівно одну крапку з комою.
Порядок перевірки: знайти розділювач, перевірити його наявність, знайти можливий другий, виділити поля, перевірити порожність, розібрати число повністю, перевірити діапазон. Якщо спочатку без перевірки виконати substr(separator + 1), значення npos може зруйнувати логіку індексів. Кожний етап має чітку причину відмови.
Для CSV з лапками потрібно пам’ятати стан «усередині цитованого поля». Кома в цьому стані є частиною тексту, а не розділювачем. Подвійна лапка може означати кінець поля або екрановану лапку, залежно від наступного символу. Незакриті лапки наприкінці рядка є помилкою, а не підставою мовчки прийняти частину запису.
Власність результатів розбору
Якщо поля потрібні лише для обробки поточного рядка, вигляди дозволяють уникнути копіювання. Але якщо записи зберігаються в довготривалому векторі, наступний getline перезапише буфер. Тоді поля мають стати власними рядками або мати іншого власника, час життя якого явно гарантований.
Повернення вектора string_view з функції, яка створила локальний рядок, є небезпечним навіть якщо тест один раз показав правильні слова. Пам’ять може ще містити старі байти, але об’єкт уже не існує. Ознака «у налагоджувачі видно текст» не є доказом чинного часу життя.
Пам’ять і обмеження розмірів
Користувацька кількість елементів повинна бути обмежена до створення вектора. Якщо від’ємне ціле перетворити на size_t, воно може стати величезним додатним значенням. Перевіряйте спочатку знаковий вхід у дозволеному діапазоні, а вже потім перетворюйте його для індексації.
Для матриці перевіряють не лише рядки та стовпці окремо, а й їх добуток. Два допустимих розміри по 100000 можуть означати десять мільярдів елементів. Верхня межа кількості комірок має відповідати задачі та можливостям середовища.
Резервування великої місткості не є безкоштовним, навіть коли size залишається 0. Не викликайте reserve перед кожним push_back із новою точною місткістю: так можна втратити переваги геометричного зростання. Якщо приблизна кінцева кількість відома, одного розумного reserve достатньо; інакше дозвольте вектору керувати буфером.
Перевірка меж на прикладі бронювання
Користувач бачить ряди 1–3 і місця 1–4, а масив має індекси 0–2 та 0–3. Спочатку перевірте обидві введені координати, потім віднімайте 1. Якщо перетворити від’ємний ряд на size_t до перевірки, він може стати великим додатним числом. Перевірка лише верхньої межі після такого перетворення ускладнить діагностику й не виправить неправильний порядок дій.
Операція бронювання має дві різні відмови: координати недопустимі або місце вже зайняте. Перша не повинна читати матрицю взагалі. Друга читає чинну комірку, але не змінює стан. Успішна дія змінює рівно одну комірку false на true. Повторення тієї самої дії не має збільшувати кількість зайнятих місць удруге.
Незалежний підсумок можна перерахувати обходом усієї матриці після серії команд. Якщо програма також веде лічильник зайнятих місць, обидва результати повинні збігатися. Така перевірка виявляє помилки оновлення лічильника, які непомітні за одним знімком карти. Для скасування бронювання потрібні симетричні перевірки: координата існує, місце було зайняте, після успіху воно вільне.
При додаванні списку імен покупців не варто зберігати паралельні матриці станів, імен і цін без явного зв’язку. Структура Seat може містити всі поля однієї комірки, а матриця – такі структури. Тоді скасування очищає узгоджений запис, а не залишає старе ім’я на вже вільному місці.
Цей приклад показує, що контейнер розв’язує питання зберігання, але інваріанти предметної області визначає автор програми. Правильний тип vector або array не доводить правильності бронювання. Потрібні чіткі передумови, зміни стану та перевірки після кожної операції.
Практичний протокол перевірки колекції
Перед запуском великого набору даних перевірте малий набір, який можна повністю прочитати. Для вектора записів це три різні записи й один дублікат. Додайте елемент на початок, усередину та в кінець; після кожної дії надрукуйте всі записи з індексами. Потім вилучіть їх у зворотному порядку. Якщо програма підтримує власні ідентифікатори, переконайтеся, що вони не змінюються разом із позиціями.
Порожній вектор потрібно перевіряти окремо, а не вважати його «тим самим випадком з нулем ітерацій». Цикл справді може не виконатися, але доступ до front, back або елемента 0 перед циклом уже буде помилкою. Так само мінімум порожньої множини не отримують автоматично зі змінної, ініціалізованої нулем. Інтерфейс повинен явно повідомити відсутність результату або заборонити порожній вхід перевіреною передумовою.
Для рядкових виглядів корисний тест не лише «чи правильно надруковано слово», а й «хто володіє цими байтами в момент друку». Намалюйте власний рядок і всі вигляди на нього. Біля кожного дописування, присвоєння та виходу з блока перевірте, чи залишаються вигляди чинними. Цей аналіз часто знаходить дефект раніше, ніж випадковий тест.
Перевірка capacity() у налагоджувачі є способом спостерігати реалізацію, а не умовою правильності алгоритму. Не пишіть тест, який вимагає конкретно capacity=8 після п’ятого додавання, якщо програма не має такої гарантованої передумови. Перевіряйте size, значення та публічні гарантії контейнера. Саме це дозволяє тому самому коду працювати після оновлення бібліотеки.
Останній крок – повторити тести після форматування виведення. Таблиця може виглядати охайно, але показувати не той запис після сортування. Порівнюйте зв’язок імені, ідентифікатора і значення, а не тільки кількість рядків або ширину стовпців. Оформлення результату має підтримувати перевірку змісту, а не приховувати помилки моделі.