shushus

Спринт 14. Функции std::uninitialized_*.

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