shushus

Спринт 14. Оператор присваивания и move-конструктор.

May 5th, 2023
417
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.62 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. vector.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5. #include <cassert>
  6. #include <memory>
  7. #include <algorithm>
  8. #include <cstdlib>
  9. #include <new>
  10. #include <utility>
  11.  
  12. template <typename T>
  13. class RawMemory {
  14. public:
  15.     RawMemory() = default;
  16.  
  17.     explicit RawMemory(size_t capacity) : buffer_(Allocate(capacity))
  18.                                         , capacity_(capacity) {}
  19.  
  20.     ~RawMemory() {Deallocate(buffer_);}
  21.    
  22.     RawMemory(const RawMemory&) = delete;
  23.     RawMemory& operator=(const RawMemory& rhs) = delete;
  24.    
  25.     RawMemory(RawMemory&& other) noexcept : buffer_(std::exchange(other.buffer_, nullptr))
  26.                                           , capacity_(std::exchange(other.capacity_, 0)) {}
  27.  
  28.     RawMemory& operator=(RawMemory&& rhs) noexcept {
  29.        
  30.         if (this != &rhs) {
  31.             buffer_ = std::move(rhs.buffer_);
  32.             capacity_ = std::move(rhs.capacity_);
  33.             rhs.buffer_ = nullptr;
  34.             rhs.capacity_ = 0;
  35.         }
  36.        
  37.         return *this;
  38.     }
  39.  
  40.     T* operator+(size_t offset) noexcept {assert(offset <= capacity_); return buffer_ + offset;}
  41.     const T* operator+(size_t offset) const noexcept {return const_cast<RawMemory&>(*this) + offset;}
  42.  
  43.     const T& operator[](size_t index) const noexcept {return const_cast<RawMemory&>(*this)[index];}
  44.     T& operator[](size_t index) noexcept {assert(index < capacity_); return buffer_[index];}
  45.  
  46.     void Swap(RawMemory& other) noexcept {std::swap(buffer_, other.buffer_); std::swap(capacity_, other.capacity_);}
  47.  
  48.     const T* GetAddress() const noexcept {return buffer_;}
  49.     T* GetAddress() noexcept {return buffer_;}
  50.     size_t Capacity() const {return capacity_;}
  51.  
  52. private:
  53.     T* buffer_ = nullptr;
  54.     size_t capacity_ = 0;
  55.    
  56.     static T* Allocate(size_t n) {return n != 0 ? static_cast<T*>(operator new(n * sizeof(T))) : nullptr;}
  57.     static void Deallocate(T* buf) noexcept {operator delete(buf);}
  58. };
  59.  
  60. template <typename T>
  61. class Vector {
  62. public:
  63.    
  64.     Vector() = default;
  65.  
  66.     explicit Vector(size_t size) : data_(size)
  67.                                  , size_(size) {std::uninitialized_value_construct_n(data_.GetAddress(), size);}
  68.    
  69.     Vector(const Vector& other) : data_(other.size_)
  70.                                 , size_(other.size_) {std::uninitialized_copy_n(other.data_.GetAddress(), size_, data_.GetAddress());}
  71.    
  72.     Vector(Vector&& other) noexcept : data_(std::move(other.data_))
  73.                                     , size_(std::exchange(other.size_, 0)) {}
  74.    
  75.     ~Vector() {std::destroy_n(data_.GetAddress(), size_);}
  76.    
  77.     size_t Size() const noexcept {return size_;}
  78.     size_t Capacity() const noexcept {return data_.Capacity();}
  79.     void Swap(Vector& other) noexcept {data_.Swap(other.data_), std::swap(size_, other.size_);}
  80.    
  81.     void Reserve(size_t new_capacity) {
  82.        
  83.         if (new_capacity <= data_.Capacity()) {
  84.             return;
  85.         }
  86.        
  87.         RawMemory<T> new_data(new_capacity);
  88.        
  89.         if constexpr (std::is_nothrow_move_constructible_v<T> || !std::is_copy_constructible_v<T>) {
  90.             std::uninitialized_move_n(data_.GetAddress(), size_, new_data.GetAddress());
  91.         } else {
  92.             std::uninitialized_copy_n(data_.GetAddress(), size_, new_data.GetAddress());
  93.         }
  94.        
  95.         std::destroy_n(data_.GetAddress(), size_);
  96.         data_.Swap(new_data);
  97.     }
  98.    
  99.     Vector& operator=(const Vector& other) {
  100.        
  101.         if (this != &other) {
  102.            
  103.             if (other.size_ <= data_.Capacity()) {
  104.                
  105.                 if (size_ <= other.size_) {
  106.                    
  107.                     std::copy(other.data_.GetAddress(),
  108.                               other.data_.GetAddress() + size_,
  109.                               data_.GetAddress());
  110.                    
  111.                     std::uninitialized_copy_n(other.data_.GetAddress() + size_,
  112.                                               other.size_ - size_,
  113.                                               data_.GetAddress() + size_);
  114.                 } else {
  115.                    
  116.                     std::copy(other.data_.GetAddress(),
  117.                               other.data_.GetAddress() + other.size_,
  118.                               data_.GetAddress());
  119.                    
  120.                     std::destroy_n(data_.GetAddress() + other.size_,
  121.                                    size_ - other.size_);
  122.                 }
  123.                
  124.                 size_ = other.size_;
  125.                
  126.             } else {              
  127.                 Vector other_copy(other);
  128.                 Swap(other_copy);
  129.             }
  130.         }
  131.        
  132.         return *this;
  133.     }
  134.  
  135.     Vector& operator=(Vector&& other) noexcept {Swap(other); return *this;}
  136.    
  137.     const T& operator[](size_t index) const noexcept {return const_cast<Vector&>(*this)[index];}
  138.     T& operator[](size_t index) noexcept {assert(index < size_); return data_[index];}
  139.  
  140. private:
  141.     RawMemory<T> data_;
  142.     size_t size_ = 0;
  143. };
  144. -----------------------------------------------------------------------
  145. main.cpp
  146. -----------------------------------------------------------------------
  147. #include "vector.h"
  148.  
  149. #include <stdexcept>
  150.  
  151. namespace {
  152.  
  153. struct Obj {
  154.  
  155.     Obj() {
  156.        
  157.         if (default_construction_throw_countdown > 0) {
  158.            
  159.             if (--default_construction_throw_countdown == 0) {
  160.                 throw std::runtime_error("Oops");
  161.             }
  162.         }
  163.        
  164.         ++num_default_constructed;
  165.     }
  166.  
  167.     explicit Obj(int id) : id(id) {++num_constructed_with_id;}
  168.  
  169.     Obj(const Obj& other) : id(other.id) {
  170.        
  171.         if (other.throw_on_copy) {
  172.             throw std::runtime_error("Oops");
  173.         }
  174.        
  175.         ++num_copied;
  176.     }
  177.  
  178.     Obj(Obj&& other) noexcept : id(other.id){++num_moved;}
  179.  
  180.     Obj& operator=(const Obj& other) = default;
  181.     Obj& operator=(Obj&& other) = default;
  182.  
  183.     ~Obj() {++num_destroyed; id = 0;}
  184.  
  185.     static int GetAliveObjectCount() {
  186.         return num_default_constructed
  187.                + num_copied
  188.                + num_moved
  189.                + num_constructed_with_id
  190.                - num_destroyed;
  191.     }
  192.  
  193.     static void ResetCounters() {
  194.         default_construction_throw_countdown = 0;
  195.         num_default_constructed = 0;
  196.         num_copied = 0;
  197.         num_moved = 0;
  198.         num_destroyed = 0;
  199.         num_constructed_with_id = 0;
  200.     }
  201.  
  202.     bool throw_on_copy = false;
  203.     int id = 0;
  204.  
  205.     static inline int default_construction_throw_countdown = 0;
  206.     static inline int num_default_constructed = 0;
  207.     static inline int num_constructed_with_id = 0;
  208.     static inline int num_copied = 0;
  209.     static inline int num_moved = 0;
  210.     static inline int num_destroyed = 0;
  211. };
  212.  
  213. }//end namespace
  214.  
  215. void Test1() {
  216.    
  217.     Obj::ResetCounters();
  218.    
  219.     const size_t SIZE = 100500;
  220.     const size_t INDEX = 10;
  221.     const int MAGIC = 42;
  222.    
  223.     {
  224.         Vector<int> v;
  225.         assert(v.Capacity() == 0);
  226.         assert(v.Size() == 0);
  227.  
  228.         v.Reserve(SIZE);
  229.         assert(v.Capacity() == SIZE);
  230.         assert(v.Size() == 0);
  231.     }
  232.    
  233.     {
  234.         Vector<int> v(SIZE);
  235.         const auto& cv(v);
  236.         assert(v.Capacity() == SIZE);
  237.         assert(v.Size() == SIZE);
  238.         assert(v[0] == 0);
  239.         assert(&v[0] == &cv[0]);
  240.         v[INDEX] = MAGIC;
  241.         assert(v[INDEX] == MAGIC);
  242.         assert(&v[100] - &v[0] == 100);
  243.  
  244.         v.Reserve(SIZE * 2);
  245.         assert(v.Size() == SIZE);
  246.         assert(v.Capacity() == SIZE * 2);
  247.         assert(v[INDEX] == MAGIC);
  248.     }
  249.    
  250.     {
  251.         Vector<int> v(SIZE);
  252.         v[INDEX] = MAGIC;
  253.         const auto v_copy(v);
  254.         assert(&v[INDEX] != &v_copy[INDEX]);
  255.         assert(v[INDEX] == v_copy[INDEX]);
  256.     }
  257.    
  258.     {
  259.         Vector<Obj> v;
  260.         v.Reserve(SIZE);
  261.         assert(Obj::GetAliveObjectCount() == 0);
  262.     }
  263.    
  264.     {
  265.         Vector<Obj> v(SIZE);
  266.         assert(Obj::GetAliveObjectCount() == SIZE);
  267.         const int old_copy_count = Obj::num_copied;
  268.         const int old_move_count = Obj::num_moved;
  269.         v.Reserve(SIZE * 2);
  270.         assert(Obj::GetAliveObjectCount() == SIZE);
  271.         assert(Obj::num_copied == old_copy_count);
  272.         assert(Obj::num_moved == old_move_count + static_cast<int>(SIZE));
  273.     }
  274.    
  275.     assert(Obj::GetAliveObjectCount() == 0);
  276. }
  277.  
  278. void Test2() {
  279.     const size_t SIZE = 100;
  280.    
  281.     Obj::ResetCounters();
  282.    
  283.     {
  284.         Obj::default_construction_throw_countdown = SIZE / 2;
  285.        
  286.         try {
  287.             Vector<Obj> v(SIZE);
  288.             assert(false && "Exception is expected");
  289.            
  290.         } catch (const std::runtime_error&) {
  291.            
  292.         } catch (...) {
  293.             assert(false && "Unexpected exception");
  294.            
  295.         }
  296.        
  297.         assert(Obj::num_default_constructed == SIZE / 2 - 1);
  298.         assert(Obj::GetAliveObjectCount() == 0);
  299.     }
  300.    
  301.     Obj::ResetCounters();
  302.    
  303.     {
  304.         Vector<Obj> v(SIZE);
  305.        
  306.         try {
  307.             v[SIZE / 2].throw_on_copy = true;
  308.             Vector<Obj> v_copy(v);
  309.             assert(false && "Exception is expected");
  310.            
  311.         } catch (const std::runtime_error&) {
  312.             assert(Obj::num_copied == SIZE / 2);
  313.            
  314.         } catch (...) {
  315.             assert(false && "Unexpected exception");
  316.         }
  317.        
  318.         assert(Obj::GetAliveObjectCount() == SIZE);
  319.     }
  320.    
  321.     Obj::ResetCounters();
  322.    
  323.     {
  324.         Vector<Obj> v(SIZE);
  325.        
  326.         try {
  327.             v[SIZE - 1].throw_on_copy = true;
  328.             v.Reserve(SIZE * 2);
  329.            
  330.         } catch (...) {
  331.             assert(false && "Unexpected exception");
  332.         }
  333.        
  334.         assert(v.Capacity() == SIZE * 2);
  335.         assert(v.Size() == SIZE);
  336.         assert(Obj::GetAliveObjectCount() == SIZE);
  337.     }
  338. }
  339.  
  340. void Test3() {
  341.     const size_t MEDIUM_SIZE = 100;
  342.     const size_t LARGE_SIZE = 250;
  343.     const int ID = 42;
  344.    
  345.     {
  346.         Obj::ResetCounters();
  347.        
  348.         Vector<int> v(MEDIUM_SIZE);
  349.        
  350.         {
  351.             auto v_copy(std::move(v));
  352.  
  353.             assert(v_copy.Size() == MEDIUM_SIZE);
  354.             assert(v_copy.Capacity() == MEDIUM_SIZE);
  355.         }
  356.        
  357.         assert(Obj::GetAliveObjectCount() == 0);
  358.     }
  359.    
  360.     {
  361.         Obj::ResetCounters();
  362.        
  363.         {
  364.             Vector<Obj> v(MEDIUM_SIZE);
  365.             v[MEDIUM_SIZE / 2].id = ID;
  366.             assert(Obj::num_default_constructed == MEDIUM_SIZE);
  367.             Vector<Obj> moved_from_v(std::move(v));
  368.             assert(moved_from_v.Size() == MEDIUM_SIZE);
  369.             assert(moved_from_v[MEDIUM_SIZE / 2].id == ID);
  370.         }
  371.        
  372.         assert(Obj::GetAliveObjectCount() == 0);
  373.  
  374.         assert(Obj::num_moved == 0);
  375.         assert(Obj::num_copied == 0);
  376.         assert(Obj::num_default_constructed == MEDIUM_SIZE);
  377.     }
  378.    
  379.     {
  380.         Obj::ResetCounters();
  381.        
  382.         Vector<Obj> v_medium(MEDIUM_SIZE);
  383.        
  384.         v_medium[MEDIUM_SIZE / 2].id = ID;
  385.         Vector<Obj> v_large(LARGE_SIZE);
  386.         v_large = v_medium;
  387.         assert(v_large.Size() == MEDIUM_SIZE);
  388.         assert(v_large.Capacity() == LARGE_SIZE);
  389.         assert(v_large[MEDIUM_SIZE / 2].id == ID);
  390.         assert(Obj::GetAliveObjectCount() == MEDIUM_SIZE + MEDIUM_SIZE);
  391.     }
  392.    
  393.     {
  394.         Obj::ResetCounters();
  395.        
  396.         Vector<Obj> v(MEDIUM_SIZE);
  397.        
  398.         {
  399.             Vector<Obj> v_large(LARGE_SIZE);
  400.             v_large[LARGE_SIZE - 1].id = ID;
  401.             v = v_large;
  402.             assert(v.Size() == LARGE_SIZE);
  403.             assert(v_large.Capacity() == LARGE_SIZE);
  404.             assert(v_large[LARGE_SIZE - 1].id == ID);
  405.             assert(Obj::GetAliveObjectCount() == LARGE_SIZE + LARGE_SIZE);
  406.         }
  407.        
  408.         assert(Obj::GetAliveObjectCount() == LARGE_SIZE);
  409.     }
  410.    
  411.     assert(Obj::GetAliveObjectCount() == 0);
  412.    
  413.     {
  414.         Obj::ResetCounters();
  415.        
  416.         Vector<Obj> v(MEDIUM_SIZE);
  417.        
  418.         v[MEDIUM_SIZE - 1].id = ID;
  419.         Vector<Obj> v_small(MEDIUM_SIZE / 2);
  420.         v_small.Reserve(MEDIUM_SIZE + 1);
  421.         const size_t num_copies = Obj::num_copied;
  422.         v_small = v;
  423.         assert(v_small.Size() == v.Size());
  424.         assert(v_small.Capacity() == MEDIUM_SIZE + 1);
  425.         v_small[MEDIUM_SIZE - 1].id = ID;
  426.         assert(Obj::num_copied - num_copies == MEDIUM_SIZE - (MEDIUM_SIZE / 2));
  427.     }
  428. }
  429.  
  430. int main() {
  431.     Test1();
  432.     Test2();
  433.     Test3();
  434. }
Advertisement
Add Comment
Please, Sign In to add comment