shizaero

Untitled

Aug 10th, 2023
680
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.51 KB | None | 0 0
  1. #include <cassert>
  2. #include <cstddef>
  3. #include <string>
  4. #include <utility>
  5.  
  6. template <typename Type>
  7. class SingleLinkedList {
  8.     // Узел списка
  9.     struct Node {
  10.         Node() = default;
  11.         Node(const Type& val, Node* next)
  12.             : value(val)
  13.             , next_node(next) {
  14.         }
  15.         Type value;
  16.         Node* next_node = nullptr;
  17.     };
  18.  
  19. public:
  20.  
  21.     SingleLinkedList() = default;
  22.    
  23.     void PushFront(const Type& value) {
  24.         head_.next_node = new Node(value, head_.next_node);
  25.         ++size_;
  26.     }
  27.    
  28.     void Clear() noexcept {
  29.         while (head_.next_node != nullptr){
  30.             auto ptr_copy = head_.next_node;
  31.             head_.next_node = ptr_copy -> next_node;
  32.             delete ptr_copy;
  33.         }
  34.         size_ = 0;
  35.     }
  36.    
  37.     // Возвращает количество элементов в списке за время O(1)
  38.     [[nodiscard]] size_t GetSize() const noexcept {
  39.         // Заглушка. Реализуйте метод самостоятельно
  40.         return size_;
  41.     }
  42.  
  43.     // Сообщает, пустой ли список за время O(1)
  44.     [[nodiscard]] bool IsEmpty() const noexcept {
  45.         return size_ != 0 ? false : true;
  46.     }
  47.  
  48. private:
  49.     // Фиктивный узел, используется для вставки "перед первым элементом"
  50.     Node head_;
  51.     size_t size_ = 0;
  52. };
  53.  
  54. void Test1() {
  55.     // Шпион, следящий за своим удалением
  56.     struct DeletionSpy {
  57.         DeletionSpy() = default;
  58.         explicit DeletionSpy(int& instance_counter) noexcept
  59.             : instance_counter_ptr_(&instance_counter)  //
  60.         {
  61.             OnAddInstance();
  62.         }
  63.         DeletionSpy(const DeletionSpy& other) noexcept
  64.             : instance_counter_ptr_(other.instance_counter_ptr_)  //
  65.         {
  66.             OnAddInstance();
  67.         }
  68.         DeletionSpy& operator=(const DeletionSpy& rhs) noexcept {
  69.             if (this != &rhs) {
  70.                 auto rhs_copy(rhs);
  71.                 std::swap(instance_counter_ptr_, rhs_copy.instance_counter_ptr_);
  72.             }
  73.             return *this;
  74.         }
  75.         ~DeletionSpy() {
  76.             OnDeleteInstance();
  77.         }
  78.  
  79.     private:
  80.         void OnAddInstance() noexcept {
  81.             if (instance_counter_ptr_) {
  82.                 ++(*instance_counter_ptr_);
  83.             }
  84.         }
  85.         void OnDeleteInstance() noexcept {
  86.             if (instance_counter_ptr_) {
  87.                 assert(*instance_counter_ptr_ != 0);
  88.                 --(*instance_counter_ptr_);
  89.             }
  90.         }
  91.  
  92.         int* instance_counter_ptr_ = nullptr;
  93.     };
  94.  
  95.     // Проверка вставки в начало
  96.     {
  97.         SingleLinkedList<int> l;
  98.         assert(l.IsEmpty());
  99.         assert(l.GetSize() == 0u);
  100.  
  101.         l.PushFront(0);
  102.         l.PushFront(1);
  103.         assert(l.GetSize() == 2);
  104.         assert(!l.IsEmpty());
  105.  
  106.         l.Clear();
  107.         assert(l.GetSize() == 0);
  108.         assert(l.IsEmpty());
  109.     }
  110.  
  111.     // Проверка фактического удаления элементов
  112.     {
  113.         int item0_counter = 0;
  114.         int item1_counter = 0;
  115.         int item2_counter = 0;
  116.         {
  117.             SingleLinkedList<DeletionSpy> list;
  118.             list.PushFront(DeletionSpy{item0_counter});
  119.             list.PushFront(DeletionSpy{item1_counter});
  120.             list.PushFront(DeletionSpy{item2_counter});
  121.  
  122.             assert(item0_counter == 1);
  123.             assert(item1_counter == 1);
  124.             assert(item2_counter == 1);
  125.             list.Clear();
  126.             assert(item0_counter == 0);
  127.             assert(item1_counter == 0);
  128.             assert(item2_counter == 0);
  129.  
  130.             list.PushFront(DeletionSpy{item0_counter});
  131.             list.PushFront(DeletionSpy{item1_counter});
  132.             list.PushFront(DeletionSpy{item2_counter});
  133.             assert(item0_counter == 1);
  134.             assert(item1_counter == 1);
  135.             assert(item2_counter == 1);
  136.         }
  137.         assert(item0_counter == 0);
  138.         assert(item1_counter == 0);
  139.         assert(item2_counter == 0);
  140.     }
  141.  
  142.     // Вспомогательный класс, бросающий исключение после создания N-копии
  143.     struct ThrowOnCopy {
  144.         ThrowOnCopy() = default;
  145.         explicit ThrowOnCopy(int& copy_counter) noexcept
  146.             : countdown_ptr(&copy_counter) {
  147.         }
  148.         ThrowOnCopy(const ThrowOnCopy& other)
  149.             : countdown_ptr(other.countdown_ptr)  //
  150.         {
  151.             if (countdown_ptr) {
  152.                 if (*countdown_ptr == 0) {
  153.                     throw std::bad_alloc();
  154.                 } else {
  155.                     --(*countdown_ptr);
  156.                 }
  157.             }
  158.         }
  159.         // Присваивание элементов этого типа не требуется
  160.         ThrowOnCopy& operator=(const ThrowOnCopy& rhs) = delete;
  161.         // Адрес счётчика обратного отсчёта. Если не равен nullptr, то уменьшается при каждом копировании.
  162.         // Как только обнулится, конструктор копирования выбросит исключение
  163.         int* countdown_ptr = nullptr;
  164.     };
  165.  
  166.     {
  167.         bool exception_was_thrown = false;
  168.         // Последовательно уменьшаем счётчик копирований до нуля, пока не будет выброшено исключение
  169.         for (int max_copy_counter = 5; max_copy_counter >= 0; --max_copy_counter) {
  170.             // Создаём непустой список
  171.             SingleLinkedList<ThrowOnCopy> list;
  172.             list.PushFront(ThrowOnCopy{});
  173.             try {
  174.                 int copy_counter = max_copy_counter;
  175.                 list.PushFront(ThrowOnCopy(copy_counter));
  176.                 // Если метод не выбросил исключение, список должен перейти в новое состояние
  177.                 assert(list.GetSize() == 2);
  178.             } catch (const std::bad_alloc&) {
  179.                 exception_was_thrown = true;
  180.                 // После выбрасывания исключения состояние списка должно остаться прежним
  181.                 assert(list.GetSize() == 1);
  182.                 break;
  183.             }
  184.         }
  185.         assert(exception_was_thrown);
  186.     }
  187. }
  188.  
  189. int main() {
  190.     Test1();
  191. }
Advertisement
Add Comment
Please, Sign In to add comment