C++ • Data Structures • Singly Linked List • Iterators • Exception Safety
В блоке 0.N) [[nodiscard]] demo меняем:
#if 0
empty.begin();
#endifна:
#if 1
empty.begin(); // намеренно игнорируем результат
#endifСобираем проект:
g++ -std=c++17 -O2 -Wall -Wextra -pedantic task1_lesson6_9_full_logs_tail_review.cpp -o task6_logsКомпилятор выводит предупреждение:
warning: ignoring return value of
'SingleLinkedList<Type>::Iterator SingleLinkedList<Type>::begin()',
declared with attribute 'nodiscard' [-Wunused-result]
begin()возвращает итератор и помечен[[nodiscard]]- строка
empty.begin();выбрасывает результат - GCC предупреждает: ignoring return value … nodiscard
👉 На выполнение программы warning не влияет.
Запускаем:
task6_logsПрограмма выводит чеклист, где каждый блок подтверждает корректность контейнера.
IsEmpty -> true— список пустsize == 0— размер корректныйbegin == end— у пустого контейнера нет элементовbefore_begin == cbefore_begin— оба указывают на dummy-head++before_begin == begin— корректная навигация++cbefore_begin == const begin— то же для const
✅ Итог: итераторы и dummy-узел работают корректно даже для пустого списка.
0.N1 stored begin() in [[maybe_unused]] variable -> OKИтератор сохранён → корректный вариант0.N2 ...Напоминание, что warning появляется при включенииempty.begin()
ℹ️ Сам warning появляется на этапе компиляции, а не во время запуска.
- Было:
[3 14 15 92 6] - После
PopFront():[14 15 92 6] - Проверка равенства →
true
- до удаления:
deletion_counter = 0 - после удаления:
deletion_counter = 1
✅ Деструктор вызван ровно один раз, утечек нет.
before_begin == cbefore_begin++before_begin == begin
✅ Можно безопасно делать insert / erase в голову списка.
InsertAfter(before_begin, 123) → {123}
Возвращаемый итератор:
- равен
begin() *it == 123
{1,2,3} → {123,1,2,3} → {123,555,1,2,3}
✅ Все expect true подтверждают:
- правильный порядок,
- корректные возвращаемые итераторы.
Ключевые строки:
- пойман
std::bad_alloc list size after throw = 3strong guarantee holds -> true
- сначала создаётся
new Node(...)(может бросить) - только потом узел привязывается к списку
Если происходит исключение — список остаётся неизменным.
- удаление первого →
{2,3,4}, возвращаетсяbegin() - удаление середины →
{1,3,4}, возвращается++begin - удаление последнего →
{1,2,3}, возвращаетсяend()
DeletionSpy снова подтверждает 1 вызов деструктора.
==, !=, <, >, <=, >= работают корректно.
- swap не копирует узлы
- итераторы “переезжают” вместе со списками
- ADL
swap()работает
- copy ctor → глубокая копия
operator=через copy-and-swap → strong guarantee
-
старый способ: 2 копии на элемент
-
tail_build:new Node(*it, nullptr)
→ 1 копия, без буферов
If all 'expect true' checks match, you demonstrated Lesson 6_9 Task1 + kept 5_9 features.
🎉 Это означает:
- все требования Lesson 6_9 выполнены
- функциональность Lesson 5_9 не сломана
- реализация корректна и безопасна