Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cassert>
- #include <cstddef>
- #include <string>
- #include <utility>
- template <typename Type>
- class SingleLinkedList {
- // Узел списка
- struct Node {
- Node() = default;
- Node(const Type& val, Node* next)
- : value(val)
- , next_node(next) {
- }
- Type value;
- Node* next_node = nullptr;
- };
- public:
- SingleLinkedList() : head_(), size_(0) {};
- ~SingleLinkedList() { Clear(); };
- // Вставляет элемент value в начало списка за время O(1)
- void PushFront(const Type& value) {
- head_.next_node = new Node(value, head_.next_node);
- ++size_;
- }
- // Очищает список за время O(N)
- void Clear() noexcept {
- while (head_.next_node)
- {
- Node* new_node = head_.next_node->next_node;
- delete head_.next_node;
- head_.next_node = new_node;
- }
- size_ = 0;
- }
- // Возвращает количество элементов в списке за время O(1)
- [[nodiscard]] size_t GetSize() const noexcept {
- return size_;
- }
- // Сообщает, пустой ли список за время O(1)
- [[nodiscard]] bool IsEmpty() const noexcept {
- return (size_ == 0) ? true : false;
- }
- private:
- // Фиктивный узел, используется для вставки "перед первым элементом"
- Node head_;
- size_t size_;
- };
- // Эта функция тестирует работу SingleLinkedList
- void Test1() {
- // Шпион, следящий за своим удалением
- struct DeletionSpy {
- DeletionSpy() = default;
- explicit DeletionSpy(int& instance_counter) noexcept
- : instance_counter_ptr_(&instance_counter) //
- {
- OnAddInstance();
- }
- DeletionSpy(const DeletionSpy& other) noexcept
- : instance_counter_ptr_(other.instance_counter_ptr_) //
- {
- OnAddInstance();
- }
- DeletionSpy& operator=(const DeletionSpy& rhs) noexcept {
- if (this != &rhs) {
- auto rhs_copy(rhs);
- std::swap(instance_counter_ptr_, rhs_copy.instance_counter_ptr_);
- }
- return *this;
- }
- ~DeletionSpy() {
- OnDeleteInstance();
- }
- private:
- void OnAddInstance() noexcept {
- if (instance_counter_ptr_) {
- ++(*instance_counter_ptr_);
- }
- }
- void OnDeleteInstance() noexcept {
- if (instance_counter_ptr_) {
- assert(*instance_counter_ptr_ != 0);
- --(*instance_counter_ptr_);
- }
- }
- int* instance_counter_ptr_ = nullptr;
- };
- // Проверка вставки в начало
- {
- SingleLinkedList<int> l;
- assert(l.IsEmpty());
- assert(l.GetSize() == 0u);
- l.PushFront(0);
- l.PushFront(1);
- assert(l.GetSize() == 2);
- assert(!l.IsEmpty());
- l.Clear();
- assert(l.GetSize() == 0);
- assert(l.IsEmpty());
- }
- // Проверка фактического удаления элементов
- {
- int item0_counter = 0;
- int item1_counter = 0;
- int item2_counter = 0;
- {
- SingleLinkedList<DeletionSpy> list;
- list.PushFront(DeletionSpy{ item0_counter });
- list.PushFront(DeletionSpy{ item1_counter });
- list.PushFront(DeletionSpy{ item2_counter });
- assert(item0_counter == 1);
- assert(item1_counter == 1);
- assert(item2_counter == 1);
- list.Clear();
- assert(item0_counter == 0);
- assert(item1_counter == 0);
- assert(item2_counter == 0);
- list.PushFront(DeletionSpy{ item0_counter });
- list.PushFront(DeletionSpy{ item1_counter });
- list.PushFront(DeletionSpy{ item2_counter });
- assert(item0_counter == 1);
- assert(item1_counter == 1);
- assert(item2_counter == 1);
- }
- assert(item0_counter == 0);
- assert(item1_counter == 0);
- assert(item2_counter == 0);
- }
- // Вспомогательный класс, бросающий исключение после создания N-копии
- struct ThrowOnCopy {
- ThrowOnCopy() = default;
- explicit ThrowOnCopy(int& copy_counter) noexcept
- : countdown_ptr(©_counter) {
- }
- ThrowOnCopy(const ThrowOnCopy& other)
- : countdown_ptr(other.countdown_ptr) //
- {
- if (countdown_ptr) {
- if (*countdown_ptr == 0) {
- throw std::bad_alloc();
- }
- else {
- --(*countdown_ptr);
- }
- }
- }
- // Присваивание элементов этого типа не требуется
- ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
- // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
- // Как только обнулится, конструктор копирования выбросит исключение
- int* countdown_ptr = nullptr;
- };
- {
- bool exception_was_thrown = false;
- // Последовательно уменьшаем счётчик копирований до нуля, пока не будет выброшено исключение
- for (int max_copy_counter = 5; max_copy_counter >= 0; --max_copy_counter) {
- // Создаём непустой список
- SingleLinkedList<ThrowOnCopy> list;
- list.PushFront(ThrowOnCopy{});
- try {
- int copy_counter = max_copy_counter;
- list.PushFront(ThrowOnCopy(copy_counter));
- // Если метод не выбросил исключение, список должен перейти в новое состояние
- assert(list.GetSize() == 2);
- }
- catch (const std::bad_alloc&) {
- exception_was_thrown = true;
- // После выбрасывания исключения состояние списка должно остаться прежним
- assert(list.GetSize() == 1);
- break;
- }
- }
- assert(exception_was_thrown);
- }
- }
- int main() {
- Test1();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement