kutuzzzov

Уро 10-2 присваивание объектов

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