Advertisement
YaMolekula

Untitled

Jan 26th, 2023
1,322
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.20 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.     PtrVector(const PtrVector& other) {
  14.         items_.reserve(other.items_.size());
  15.         try {
  16.             for (auto p : other.items_) {
  17.                 auto p_copy = p ? new T(*p) : nullptr;
  18.                 items_.push_back(p_copy);
  19.             }
  20.         } catch (...) {
  21.             DeleteItems();
  22.             throw;
  23.         }
  24.     }
  25.  
  26.     // Деструктор удаляет объекты в куче, на которые ссылаются указатели,
  27.     // в векторе items_
  28.     ~PtrVector() {
  29.         DeleteItems();
  30.     }
  31.  
  32.     // Возвращает ссылку на вектор указателей
  33.     vector<T*>& GetItems() noexcept {
  34.         return items_;
  35.     }
  36.  
  37.     // Возвращает константную ссылку на вектор указателей
  38.     vector<T*> const& GetItems() const noexcept {
  39.         return items_;
  40.     }
  41.    
  42.     PtrVector& operator=(const PtrVector& rhs) {
  43.         if (this != &rhs) {
  44.             PtrVector<T> rhs_copy(rhs);
  45.             items_.swap(rhs_copy.GetItems());
  46.         }
  47.         return *this;
  48.     }
  49.  
  50. private:
  51.     void DeleteItems() noexcept {
  52.         for (auto p : items_) {
  53.             delete p;
  54.         }
  55.     }
  56.  
  57.     vector<T*> items_;
  58. };
  59.  
  60. template <typename T>
  61. class ScopedPtr {
  62. public:
  63.     ScopedPtr() = default;
  64.  
  65.     explicit ScopedPtr(T* raw_ptr) noexcept
  66.         : ptr_(raw_ptr) {
  67.     }
  68.  
  69.     // Запрещаем копирование указателя
  70.     ScopedPtr(const ScopedPtr&) = delete;
  71.  
  72.     ~ScopedPtr() {
  73.         delete ptr_;
  74.     }
  75.  
  76.     T* GetRawPtr() const noexcept {
  77.         return ptr_;
  78.     }
  79.  
  80.     T* Release() noexcept {
  81.         T* p = ptr_;
  82.         ptr_ = nullptr;
  83.         return p;
  84.     }
  85.  
  86.     explicit operator bool() const {
  87.         return ptr_ != nullptr;
  88.     }
  89.  
  90.     T* operator->() const {
  91.         using namespace std::literals;
  92.         if (!ptr_) {
  93.             throw std::logic_error("Scoped ptr is null"s);
  94.         }
  95.         return ptr_;
  96.     }
  97.  
  98.     T& operator*() const {
  99.         using namespace std::literals;
  100.         if (!ptr_) {
  101.             throw std::logic_error("Scoped ptr is null"s);
  102.         }
  103.         return *ptr_;
  104.     }
  105.  
  106. private:
  107.     T* ptr_ = nullptr;
  108. };
  109.  
  110. class Tentacle {
  111. public:
  112.     explicit Tentacle(int id) noexcept
  113.         : id_(id) {
  114.     }
  115.  
  116.     int GetId() const noexcept {
  117.         return id_;
  118.     }
  119.  
  120.     Tentacle* GetLinkedTentacle() const noexcept {
  121.         return linked_tentacle_;
  122.     }
  123.     void LinkTo(Tentacle& tentacle) noexcept {
  124.         linked_tentacle_ = &tentacle;
  125.     }
  126.     void Unlink() noexcept {
  127.         linked_tentacle_ = nullptr;
  128.     }
  129.  
  130. private:
  131.     int id_ = 0;
  132.     Tentacle* linked_tentacle_ = nullptr;
  133. };
  134.  
  135. // Осьминог
  136. class Octopus {
  137. public:
  138.     Octopus()
  139.         : Octopus(8) {
  140.     }
  141.  
  142.     explicit Octopus(int num_tentacles) {
  143.         //ScopedPtr<Tentacle> t = nullptr;
  144.         try {
  145.             for (int i = 1; i <= num_tentacles; ++i) {
  146.                 ScopedPtr<Tentacle> t = ScopedPtr(new Tentacle(i));      // Может выбросить исключение bad_alloc
  147.                 tentacles_.GetItems().push_back(
  148.                     t.Release()
  149.                 );  // Может выбросить исключение bad_alloc
  150.                 // Обнуляем указатель на щупальце, которое уже добавили в tentacles_,
  151.                 // чтобы не удалить его в обработчике catch повторно
  152.                 //t = nullptr;
  153.             }
  154.         } catch (const std::bad_alloc&) {
  155.             // Удаляем щупальца, которые успели попасть в контейнер tentacles_
  156.             Cleanup();
  157.             // Удаляем щупальце, которое создали, но не добавили в tentacles_
  158.             //delete t;
  159.             // Конструктор не смог создать осьминога с восемью щупальцами,
  160.             // поэтому выбрасываем исключение, чтобы сообщить вызывающему коду об ошибке
  161.             // throw без параметров внутри catch выполняет ПЕРЕВЫБРОС пойманного исключения
  162.             throw;
  163.         }
  164.     }
  165.    
  166.     //Octopus(const Octopus& other) {
  167.     //    tentacles_ = PtrVector<Tentacle>(other.tentacles_);
  168.     //}
  169.  
  170.     ~Octopus() {
  171.         // Осьминог владеет объектами в динамической памяти (щупальца),
  172.         // которые должны быть удалены при его разрушении.
  173.         // Деструктор - лучшее место, чтобы прибраться за собой.
  174.         Cleanup();
  175.     }
  176.  
  177.     // Добавляет новое щупальце с идентификатором,
  178.     // равным (количество_щупалец + 1):
  179.     // 1, 2, 3, ...
  180.     // Возвращает ссылку на добавленное щупальце
  181.     // Tentacle& AddTentacle() {
  182.     //     Реализуйте добавление щупальца самостоятельно
  183.     // }
  184.     Tentacle& AddTentacle() {
  185.         try {
  186.             ScopedPtr<Tentacle> t = ScopedPtr(
  187.                 new Tentacle(GetTentacleCount()+1)
  188.             );
  189.             tentacles_.GetItems().push_back(
  190.                 t.Release()
  191.             );
  192.             return *tentacles_.GetItems().back();
  193.         } catch (const std::bad_alloc&) {
  194.             Cleanup();
  195.             //delete t;
  196.             throw;
  197.         }
  198.     }
  199.  
  200.     int GetTentacleCount() const noexcept {
  201.         return static_cast<int>(
  202.             tentacles_.GetItems().size()
  203.         );
  204.     }
  205.  
  206.     const Tentacle& GetTentacle(size_t index) const {
  207.         return *tentacles_.GetItems().at(index);
  208.     }
  209.     Tentacle& GetTentacle(size_t index) {
  210.         return *tentacles_.GetItems().at(index);
  211.     }
  212.  
  213. private:
  214.     void Cleanup() {
  215.         // Удаляем щупальца осьминога из динамической памяти
  216.         //for (Tentacle* t : tentacles_) {
  217.         //    delete t;
  218.         //}
  219.         // Очищаем массив указателей на щупальца
  220.         //tentacles_.clear();
  221.         //tentacles_=PtrVector<Tentacle>();
  222.     }
  223.  
  224.     // Вектор хранит указатели на щупальца. Сами объекты щупалец находятся в куче
  225.     PtrVector<Tentacle> tentacles_;
  226. };
  227.  
  228.  
  229. int main() {
  230.     // Проверка присваивания осьминогов
  231.     {
  232.         Octopus octopus1(3);
  233.  
  234.         // Настраиваем состояние исходного осьминога
  235.         octopus1.GetTentacle(2).LinkTo(octopus1.GetTentacle(1));
  236.  
  237.         // До присваивания octopus2 имеет своё собственное состояние
  238.         Octopus octopus2(10);
  239.  
  240.         octopus2 = octopus1;
  241.  
  242.         // После присваивания осьминогов щупальца копии имеют то же состояние,
  243.         // что и щупальца присваиваемого объекта
  244.         assert(octopus2.GetTentacleCount() == octopus1.GetTentacleCount());
  245.         for (int i = 0; i < octopus2.GetTentacleCount(); ++i) {
  246.             auto& tentacle1 = octopus1.GetTentacle(i);
  247.             auto& tentacle2 = octopus2.GetTentacle(i);
  248.             assert(&tentacle2 != &tentacle1);
  249.             assert(tentacle2.GetId() == tentacle1.GetId());
  250.             assert(tentacle2.GetLinkedTentacle() == tentacle1.GetLinkedTentacle());
  251.         }
  252.     }
  253.  
  254.     // Проверка самоприсваивания осьминогов
  255.     {
  256.         Octopus octopus(3);
  257.  
  258.         // Настраиваем состояние осьминога
  259.         octopus.GetTentacle(0).LinkTo(octopus.GetTentacle(1));
  260.  
  261.         vector<pair<Tentacle*, Tentacle*>> tentacles;
  262.         // Сохраняем информацию о щупальцах осьминога и его копии
  263.         for (int i = 0; i < octopus.GetTentacleCount(); ++i) {
  264.             tentacles.push_back({&octopus.GetTentacle(i), octopus.GetTentacle(i).GetLinkedTentacle()});
  265.         }
  266.  
  267.         // Выполняем самоприсваивание
  268.         octopus = octopus;
  269.  
  270.         // После самоприсваивания состояние осьминога не должно измениться
  271.         assert(octopus.GetTentacleCount() == static_cast<int>(tentacles.size()));
  272.         for (int i = 0; i < octopus.GetTentacleCount(); ++i) {
  273.             auto& tentacle_with_link = tentacles.at(i);
  274.             assert(&octopus.GetTentacle(i) == tentacle_with_link.first);
  275.             assert(octopus.GetTentacle(i).GetLinkedTentacle() == tentacle_with_link.second);
  276.         }
  277.     }
  278. }
  279.  
  280. // Эта функция main тестирует шаблон класса PtrVector
  281. /*int main() {
  282.     struct CopyingSpy {
  283.         CopyingSpy(int& copy_count, int& deletion_count)
  284.             : copy_count_(copy_count)
  285.             , deletion_count_(deletion_count) {
  286.         }
  287.         CopyingSpy(const CopyingSpy& rhs)
  288.             : copy_count_(rhs.copy_count_)          // счётчик копирований
  289.             , deletion_count_(rhs.deletion_count_)  // счётчик удалений
  290.         {
  291.             if (rhs.throw_on_copy_) {
  292.                 throw runtime_error("copy construction failed"s);
  293.             }
  294.             ++copy_count_;
  295.         }
  296.         ~CopyingSpy() {
  297.             ++deletion_count_;
  298.         }
  299.         void ThrowOnCopy() {
  300.             throw_on_copy_ = true;
  301.         }
  302.  
  303.     private:
  304.         int& copy_count_;
  305.         int& deletion_count_;
  306.         bool throw_on_copy_ = false;
  307.     };
  308.  
  309.     // Проверка присваивания
  310.     {
  311.         int item0_copy_count = 0;
  312.         int item0_deletion_count = 0;
  313.         {
  314.             PtrVector<CopyingSpy> v;
  315.  
  316.             v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
  317.             v.GetItems().push_back(nullptr);
  318.             {
  319.                 PtrVector<CopyingSpy> v_copy;
  320.                 v_copy = v;
  321.                 assert(v_copy.GetItems().size() == v.GetItems().size());
  322.                 assert(v_copy.GetItems().at(0) != v.GetItems().at(0));
  323.                 assert(v_copy.GetItems().at(1) == nullptr);
  324.                 assert(item0_copy_count == 1);
  325.                 assert(item0_deletion_count == 0);
  326.             }
  327.             assert(item0_deletion_count == 1);
  328.         }
  329.         assert(item0_deletion_count == 2);
  330.     }
  331.  
  332.     // Проверка корректности самоприсваивания
  333.     {
  334.         int item0_copy_count = 0;
  335.         int item0_deletion_count = 0;
  336.  
  337.         PtrVector<CopyingSpy> v;
  338.         v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
  339.         CopyingSpy* first_item = v.GetItems().front();
  340.  
  341.         v = v;
  342.         assert(v.GetItems().size() == 1);
  343.         // При самоприсваивании объекты должны быть расположены по тем же адресам
  344.         assert(v.GetItems().front() == first_item);
  345.         assert(item0_copy_count == 0);
  346.         assert(item0_deletion_count == 0);
  347.     }
  348.  
  349.     // Проверка обеспечения строгой гарантии безопасности исключений при присваивании
  350.     {
  351.         int item0_copy_count = 0;
  352.         int item0_deletion_count = 0;
  353.  
  354.         int item1_copy_count = 0;
  355.         int item1_deletion_count = 0;
  356.  
  357.         // v хранит 2 элемента
  358.         PtrVector<CopyingSpy> v;
  359.         v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
  360.         v.GetItems().push_back(new CopyingSpy(item1_copy_count, item1_deletion_count));
  361.  
  362.         int other_item0_copy_count = 0;
  363.         int other_item0_deletion_count = 0;
  364.         // other_vector хранит 1 элемент, при копировании которого будет выброшено исключение
  365.         PtrVector<CopyingSpy> other_vector;
  366.         other_vector.GetItems().push_back(new CopyingSpy(other_item0_copy_count, other_item0_deletion_count));
  367.         other_vector.GetItems().front()->ThrowOnCopy();
  368.  
  369.         // Сохраняем массив указателей
  370.         auto v_items(v.GetItems());
  371.  
  372.         try {
  373.             v = other_vector;
  374.             // Операция должна выбросить исключение
  375.             assert(false);
  376.         } catch (const runtime_error&) {
  377.         }
  378.  
  379.         // Элементы массива должны остаться прежними
  380.         assert(v.GetItems() == v_items);
  381.         assert(item0_copy_count == 0);
  382.         assert(item1_copy_count == 0);
  383.         assert(other_item0_copy_count == 0);
  384.     }
  385. }*/
  386.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement