shushus

Спринт 14. Упрощаем работу с сырой памятью.

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