Advertisement
chevengur

СПРИНТ № 7 | Модель памяти в C++ | Урок 10: Присваивание объектов 1/2

Apr 23rd, 2024
753
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.56 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cassert>
  3. #include <stdexcept>
  4. #include <vector>
  5. #include <iostream>
  6.  
  7. using namespace std;
  8.  
  9. // Используйте эту заготовку PtrVector или замените её на свою реализацию
  10. template <typename T>
  11. class PtrVector {
  12. public:
  13.     PtrVector() = default;
  14.  
  15.     // Создаёт вектор указателей на копии объектов из other
  16.     PtrVector(const PtrVector& other) {
  17.         // Резервируем место в vector-е для хранения нужного количества элементов
  18.         // Благодаря этому при push_back не будет выбрасываться исключение
  19.         items_.reserve(other.items_.size());
  20.  
  21.         try {
  22.             for (auto p : other.items_) {
  23.                 // Копируем объект, если указатель на него ненулевой
  24.                 auto p_copy = p ? new T(*p) : nullptr;  // new может выбросить исключение
  25.  
  26.                 // Не выбросит исключение, т. к. в vector память уже зарезервирована
  27.                 items_.push_back(p_copy);
  28.             }
  29.         }
  30.         catch (...) {
  31.             // удаляем элементы в векторе и перевыбрасываем пойманное исключение
  32.             DeleteItems();
  33.             throw;
  34.         }
  35.     }
  36.  
  37.     // Деструктор удаляет объекты в куче, на которые ссылаются указатели,
  38.     // в векторе items_
  39.     ~PtrVector() {
  40.         DeleteItems();
  41.     }
  42.  
  43.     PtrVector& operator=(const PtrVector& rhs)
  44.     {
  45.         if (this != &rhs)
  46.         {
  47.             auto rhs_copy(rhs);
  48.             swap_(rhs_copy);
  49.                        
  50.         }
  51.         return *this;
  52.     }
  53.  
  54.     void swap_(PtrVector& other) noexcept
  55.     {
  56.         swap(other.items_, this->items_);
  57.     }
  58.  
  59.  
  60.     // Возвращает ссылку на вектор указателей
  61.     vector<T*>& GetItems() noexcept {
  62.         return items_;
  63.     }
  64.  
  65.     // Возвращает константную ссылку на вектор указателей
  66.     vector<T*> const& GetItems() const noexcept {
  67.         return items_;
  68.     }
  69.  
  70. private:
  71.     void DeleteItems() noexcept {
  72.         for (auto p : items_) {
  73.             delete p;
  74.         }
  75.     }
  76.  
  77.     vector<T*> items_;
  78. };
  79.  
  80. //#include "octopus.h"
  81.  
  82.  
  83. using namespace std;
  84.  
  85. // Эта функция main тестирует шаблон класса PtrVector
  86. int main() {
  87.     struct CopyingSpy {
  88.         CopyingSpy(int& copy_count, int& deletion_count)
  89.             : copy_count_(copy_count)
  90.             , deletion_count_(deletion_count) {
  91.         }
  92.         CopyingSpy(const CopyingSpy& rhs)
  93.             : copy_count_(rhs.copy_count_)          // счётчик копирований
  94.             , deletion_count_(rhs.deletion_count_)  // счётчик удалений
  95.         {
  96.             if (rhs.throw_on_copy_) {
  97.                 throw runtime_error("copy construction failed"s);
  98.             }
  99.             ++copy_count_;
  100.         }
  101.         ~CopyingSpy() {
  102.             ++deletion_count_;
  103.         }
  104.         void ThrowOnCopy() {
  105.             throw_on_copy_ = true;
  106.         }
  107.  
  108.     private:
  109.         int& copy_count_;
  110.         int& deletion_count_;
  111.         bool throw_on_copy_ = false;
  112.     };
  113.  
  114.     // Проверка присваивания
  115.     {
  116.         int item0_copy_count = 0;
  117.         int item0_deletion_count = 0;
  118.         {
  119.             PtrVector<CopyingSpy> v;
  120.  
  121.             v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
  122.             v.GetItems().push_back(nullptr);
  123.             {
  124.                 PtrVector<CopyingSpy> v_copy;
  125.                 v_copy = v;
  126.                 assert(v_copy.GetItems().size() == v.GetItems().size());
  127.                 assert(v_copy.GetItems().at(0) != v.GetItems().at(0));
  128.                 assert(v_copy.GetItems().at(1) == nullptr);
  129.                 assert(item0_copy_count == 1);
  130.                 assert(item0_deletion_count == 0);
  131.             }
  132.             assert(item0_deletion_count == 1);
  133.         }
  134.         assert(item0_deletion_count == 2);
  135.     }
  136.  
  137.     // Проверка корректности самоприсваивания
  138.     {
  139.         int item0_copy_count = 0;
  140.         int item0_deletion_count = 0;
  141.  
  142.         PtrVector<CopyingSpy> v;
  143.         v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
  144.         CopyingSpy* first_item = v.GetItems().front();
  145.  
  146.         v = v;
  147.         assert(v.GetItems().size() == 1);
  148.         // При самоприсваивании объекты должны быть расположены по тем же адресам
  149.         assert(v.GetItems().front() == first_item);
  150.         assert(item0_copy_count == 0);
  151.         assert(item0_deletion_count == 0);
  152.     }
  153.  
  154.     // Проверка обеспечения строгой гарантии безопасности исключений при присваивании
  155.     {
  156.         int item0_copy_count = 0;
  157.         int item0_deletion_count = 0;
  158.  
  159.         int item1_copy_count = 0;
  160.         int item1_deletion_count = 0;
  161.  
  162.         // v хранит 2 элемента
  163.         PtrVector<CopyingSpy> v;
  164.         v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
  165.         v.GetItems().push_back(new CopyingSpy(item1_copy_count, item1_deletion_count));
  166.  
  167.         int other_item0_copy_count = 0;
  168.         int other_item0_deletion_count = 0;
  169.         // other_vector хранит 1 элемент, при копировании которого будет выброшено исключение
  170.         PtrVector<CopyingSpy> other_vector;
  171.         other_vector.GetItems().push_back(new CopyingSpy(other_item0_copy_count, other_item0_deletion_count));
  172.         other_vector.GetItems().front()->ThrowOnCopy();
  173.  
  174.         // Сохраняем массив указателей
  175.         auto v_items(v.GetItems());
  176.  
  177.         try {
  178.             v = other_vector;
  179.             // Операция должна выбросить исключение
  180.             assert(false);
  181.         }
  182.         catch (const runtime_error&) {
  183.         }
  184.  
  185.         // Элементы массива должны остаться прежними
  186.         assert(v.GetItems() == v_items);
  187.         assert(item0_copy_count == 0);
  188.         assert(item1_copy_count == 0);
  189.         assert(other_item0_copy_count == 0);
  190.     }
  191. }
  192.  
  193.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement