shushus

Спринт 14. Обработка исключений.

May 5th, 2023
320
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.44 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. vector.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5. #include <cassert>
  6. #include <cstdlib>
  7. #include <new>
  8. #include <utility>
  9.  
  10. template <typename T>
  11. class Vector {
  12. public:
  13.    
  14.     Vector() = default;
  15.  
  16.     explicit Vector(size_t size) : data_(Allocate(size))
  17.                                  , capacity_(size)
  18.                                  , size_(size) {      
  19.         size_t i = 0;    
  20.         try {          
  21.             for (; i != size; ++i) {
  22.                 new (data_ + i) T();
  23.             }
  24.            
  25.         } catch (...) {
  26.  
  27.             DestroyN(data_, i);
  28.             Deallocate(data_);
  29.             throw;
  30.         }
  31.     }
  32.    
  33.     ~Vector() {DestroyN(data_, size_); Deallocate(data_);}
  34.    
  35.     Vector(const Vector& other) : data_(Allocate(other.size_))
  36.                                 , capacity_(other.size_)
  37.                                 , size_(other.size_) {
  38.        
  39.         size_t i = 0;    
  40.         try {
  41.             for (; i != other.size_; ++i) {
  42.                 CopyConstruct(data_ + i, other.data_[i]);
  43.             }
  44.  
  45.         } catch (...) {
  46.  
  47.             DestroyN(data_, i);
  48.             Deallocate(data_);
  49.             throw;
  50.         }
  51.     }
  52.    
  53.     size_t Size() const noexcept {return size_;}
  54.     size_t Capacity() const noexcept {return capacity_;}
  55.    
  56.     void Reserve(size_t new_capacity) {
  57.        
  58.         if (new_capacity <= capacity_) {
  59.             return;
  60.         }
  61.        
  62.         T* new_data = nullptr;
  63.        
  64.         try {
  65.             new_data = Allocate(new_capacity);
  66.            
  67.         } catch (...) {
  68.             Deallocate(new_data);
  69.             throw;
  70.         }
  71.        
  72.         size_t i = 0;
  73.         try {
  74.             for (; i != size_; ++i) {
  75.                 CopyConstruct(new_data + i, data_[i]);
  76.             }
  77.            
  78.         } catch (...) {
  79.             DestroyN(new_data, i);
  80.             Deallocate(new_data);
  81.             throw;
  82.         }
  83.  
  84.         DestroyN(data_, size_);
  85.         Deallocate(data_);
  86.  
  87.         data_ = new_data;
  88.         capacity_ = new_capacity;
  89.     }
  90.    
  91.     const T& operator[](size_t index) const noexcept {return const_cast<Vector&>(*this)[index];}
  92.     T& operator[](size_t index) noexcept {assert(index < size_); return data_[index];}
  93.  
  94. private:
  95.     T* data_ = nullptr;
  96.     size_t capacity_ = 0;
  97.     size_t size_ = 0;
  98.  
  99.     static T* Allocate(size_t n) {return n != 0 ? static_cast<T*>(operator new(n * sizeof(T))) : nullptr;}
  100.     static void Deallocate(T* buf) noexcept {operator delete(buf);}
  101.  
  102.     static void CopyConstruct(T* buf, const T& elem) {new (buf) T(elem);}
  103.     static void Destroy(T* buf) noexcept {buf->~T();}
  104.    
  105.     static void DestroyN(T* buf, size_t n) noexcept {
  106.        
  107.         for (size_t i = 0; i != n; ++i) {
  108.             Destroy(buf + i);
  109.         }
  110.     }
  111. };
  112. -----------------------------------------------------------------------
  113. main.cpp
  114. -----------------------------------------------------------------------
  115. #include "vector.h"
  116.  
  117. #include <stdexcept>
  118.  
  119. namespace {
  120.  
  121. struct Obj {
  122.    
  123.     Obj() {
  124.         if (default_construction_throw_countdown > 0) {
  125.            
  126.             if (--default_construction_throw_countdown == 0) {
  127.                
  128.                 throw std::runtime_error("Oops");
  129.             }
  130.         }
  131.        
  132.         ++num_default_constructed;
  133.     }
  134.  
  135.     Obj(const Obj& other) {
  136.        
  137.         if (other.throw_on_copy) {
  138.            
  139.             throw std::runtime_error("Oops");
  140.         }
  141.        
  142.         ++num_copied;
  143.     }
  144.  
  145.     Obj(Obj&& /*other*/) noexcept {++num_moved;}
  146.  
  147.     Obj& operator=(const Obj& other) = default;
  148.     Obj& operator=(Obj&& other) = default;
  149.  
  150.     ~Obj() {++num_destroyed;}
  151.  
  152.     static int GetAliveObjectCount() {return num_default_constructed + num_copied + num_moved - num_destroyed;}
  153.  
  154.     static void ResetCounters() {
  155.         default_construction_throw_countdown = 0;
  156.         num_default_constructed = 0;
  157.         num_copied = 0;
  158.         num_moved = 0;
  159.         num_destroyed = 0;
  160.     }
  161.  
  162.     bool throw_on_copy = false;
  163.  
  164.     static inline int default_construction_throw_countdown = 0;
  165.     static inline int num_default_constructed = 0;
  166.     static inline int num_copied = 0;
  167.     static inline int num_moved = 0;
  168.     static inline int num_destroyed = 0;
  169. };
  170.  
  171. }//end namespace
  172.  
  173. void Test1() {
  174.     Obj::ResetCounters();
  175.    
  176.     const size_t SIZE = 100500;
  177.     const size_t INDEX = 10;
  178.     const int MAGIC = 42;
  179.    
  180.     {
  181.         Vector<int> v;
  182.         assert(v.Capacity() == 0);
  183.         assert(v.Size() == 0);
  184.  
  185.         v.Reserve(SIZE);
  186.         assert(v.Capacity() == SIZE);
  187.         assert(v.Size() == 0);
  188.     }
  189.    
  190.     {
  191.         Vector<int> v(SIZE);
  192.         const auto& cv(v);
  193.         assert(v.Capacity() == SIZE);
  194.         assert(v.Size() == SIZE);
  195.         assert(v[0] == 0);
  196.         assert(&v[0] == &cv[0]);
  197.         v[INDEX] = MAGIC;
  198.         assert(v[INDEX] == MAGIC);
  199.         assert(&v[100] - &v[0] == 100);
  200.  
  201.         v.Reserve(SIZE * 2);
  202.         assert(v.Size() == SIZE);
  203.         assert(v.Capacity() == SIZE * 2);
  204.         assert(v[INDEX] == MAGIC);
  205.     }
  206.    
  207.     {
  208.         Vector<int> v(SIZE);
  209.         v[INDEX] = MAGIC;
  210.         const auto v_copy(v);
  211.         assert(&v[INDEX] != &v_copy[INDEX]);
  212.         assert(v[INDEX] == v_copy[INDEX]);
  213.     }
  214.    
  215.     {
  216.         Vector<Obj> v;
  217.         v.Reserve(SIZE);
  218.         assert(Obj::GetAliveObjectCount() == 0);
  219.     }
  220.    
  221.     {
  222.         Vector<Obj> v(SIZE);
  223.         assert(Obj::GetAliveObjectCount() == SIZE);
  224.         v.Reserve(SIZE * 2);
  225.         assert(Obj::GetAliveObjectCount() == SIZE);
  226.     }
  227.    
  228.     assert(Obj::GetAliveObjectCount() == 0);
  229. }
  230.  
  231. void Test2() {
  232.     const size_t SIZE = 100;
  233.     Obj::ResetCounters();
  234.    
  235.     {
  236.         Obj::default_construction_throw_countdown = SIZE / 2;
  237.        
  238.         try {
  239.             Vector<Obj> v(SIZE);
  240.             assert(false && "Exception is expected");
  241.            
  242.         } catch (const std::runtime_error&) {
  243.            
  244.         } catch (...) {
  245.             assert(false && "Unexpected exception");
  246.         }
  247.        
  248.         assert(Obj::num_default_constructed == SIZE / 2 - 1);
  249.         assert(Obj::GetAliveObjectCount() == 0);
  250.     }
  251.    
  252.     Obj::ResetCounters();
  253.    
  254.     {
  255.         Vector<Obj> v(SIZE);
  256.        
  257.         try {
  258.             v[SIZE / 2].throw_on_copy = true;
  259.             Vector<Obj> v_copy(v);
  260.             assert(false && "Exception is expected");
  261.            
  262.         } catch (const std::runtime_error&) {
  263.             assert(Obj::num_copied == SIZE / 2);
  264.            
  265.         } catch (...) {
  266.             assert(false && "Unexpected exception");
  267.         }
  268.        
  269.         assert(Obj::GetAliveObjectCount() == SIZE);
  270.     }
  271.    
  272.     Obj::ResetCounters();
  273.    
  274.     {
  275.         Vector<Obj> v(SIZE);
  276.        
  277.         try {
  278.             v[SIZE - 1].throw_on_copy = true;
  279.             v.Reserve(SIZE * 2);
  280.             assert(false && "Exception is expected");
  281.            
  282.         } catch (const std::runtime_error&) {
  283.             assert(Obj::num_copied == SIZE - 1);
  284.            
  285.         } catch (...) {
  286.             assert(false && "Unexpected exception");
  287.         }
  288.        
  289.         assert(v.Capacity() == SIZE);
  290.         assert(v.Size() == SIZE);
  291.         assert(Obj::GetAliveObjectCount() == SIZE);
  292.     }
  293. }
  294.  
  295. int main() {
  296.     Test1();
  297.     Test2();
  298. }
Advertisement
Add Comment
Please, Sign In to add comment