Advertisement
kutuzzzov

Урок 6 Упрощаем работу с сырой памятью

Jul 18th, 2023
892
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.37 KB | None | 0 0
  1. #pragma once
  2. #include <cassert>
  3. #include <cstdlib>
  4. #include <new>
  5. #include <utility>
  6.  
  7. template <typename T>
  8. class RawMemory {
  9. public:
  10.     RawMemory() = default;
  11.  
  12.     explicit RawMemory(size_t capacity)
  13.         : buffer_(Allocate(capacity))
  14.         , capacity_(capacity) {
  15.     }
  16.  
  17.     ~RawMemory() {
  18.         Deallocate(buffer_);
  19.     }
  20.  
  21.     T* operator+(size_t offset) noexcept {
  22.         // Разрешается получать адрес ячейки памяти, следующей за последним элементом массива
  23.         assert(offset <= capacity_);
  24.         return buffer_ + offset;
  25.     }
  26.  
  27.     const T* operator+(size_t offset) const noexcept {
  28.         return const_cast<RawMemory&>(*this) + offset;
  29.     }
  30.  
  31.     const T& operator[](size_t index) const noexcept {
  32.         return const_cast<RawMemory&>(*this)[index];
  33.     }
  34.  
  35.     T& operator[](size_t index) noexcept {
  36.         assert(index < capacity_);
  37.         return buffer_[index];
  38.     }
  39.  
  40.     void Swap(RawMemory& other) noexcept {
  41.         std::swap(buffer_, other.buffer_);
  42.         std::swap(capacity_, other.capacity_);
  43.     }
  44.  
  45.     const T* GetAddress() const noexcept {
  46.         return buffer_;
  47.     }
  48.  
  49.     T* GetAddress() noexcept {
  50.         return buffer_;
  51.     }
  52.  
  53.     size_t Capacity() const {
  54.         return capacity_;
  55.     }
  56.  
  57. private:
  58.     // Выделяет сырую память под n элементов и возвращает указатель на неё
  59.     static T* Allocate(size_t n) {
  60.         return n != 0 ? static_cast<T*>(operator new(n * sizeof(T))) : nullptr;
  61.     }
  62.  
  63.     // Освобождает сырую память, выделенную ранее по адресу buf при помощи Allocate
  64.     static void Deallocate(T* buf) noexcept {
  65.         operator delete(buf);
  66.     }
  67.  
  68.     T* buffer_ = nullptr;
  69.     size_t capacity_ = 0;
  70. };
  71.  
  72. template <typename T>
  73. class Vector {
  74. public:
  75.     Vector() = default;
  76.  
  77.     explicit Vector(size_t size)
  78.         : data_(size)
  79.         , size_(size)
  80.     {
  81.         size_t counter = 0;
  82.         try {
  83.             for (; counter != size; ++counter) {
  84.                 new (data_ + counter) T();
  85.             }
  86.         }
  87.         catch (...) {
  88.             DestroyN(data_.GetAddress(), counter);
  89.             throw;
  90.         }
  91.     }
  92.  
  93.     Vector(const Vector& other)
  94.         : data_(other.size_)
  95.         , size_(other.size_)
  96.     {
  97.         size_t counter = 0;
  98.         try {
  99.             for (; counter != other.size_; ++counter) {
  100.                 CopyConstruct(data_.GetAddress() + counter, other.data_[counter]);
  101.             }
  102.         }
  103.         catch (...) {
  104.             DestroyN(data_.GetAddress(), counter);
  105.             throw;
  106.         }
  107.     }
  108.  
  109.     ~Vector() {
  110.         DestroyN(data_.GetAddress(), size_);
  111.     }
  112.  
  113.     size_t Size() const noexcept {
  114.         return size_;
  115.     }
  116.  
  117.     size_t Capacity() const noexcept {
  118.         return data_.Capacity();
  119.     }
  120.  
  121.     void Reserve(size_t new_capacity) {
  122.         if (new_capacity <= data_.Capacity()) {
  123.             return;
  124.         }
  125.         size_t counter = 0;
  126.         RawMemory<T> new_data(new_capacity);
  127.         try {
  128.             for (; counter != size_; ++counter) {
  129.                 CopyConstruct(new_data.GetAddress() + counter, data_[counter]);
  130.             }
  131.             DestroyN(data_.GetAddress(), size_);
  132.             data_.Swap(new_data);
  133.         }
  134.         catch (...) {
  135.             DestroyN(new_data.GetAddress(), counter);
  136.             throw;
  137.         }
  138.     }
  139.  
  140.     const T& operator[](size_t index) const noexcept {
  141.         return const_cast<Vector&>(*this)[index];
  142.     }
  143.  
  144.     T& operator[](size_t index) noexcept {
  145.         assert(index < size_);
  146.         return data_[index];
  147.     }
  148.  
  149. private:
  150.     // Вызывает деструкторы n объектов массива по адресу buf
  151.     static void DestroyN(T* buf, size_t n) noexcept {
  152.         for (size_t i = 0; i != n; ++i) {
  153.             Destroy(buf + i);
  154.         }
  155.     }
  156.  
  157.     // Создаёт копию объекта elem в сырой памяти по адресу buf
  158.     static void CopyConstruct(T* buf, const T& elem) {
  159.         new (buf) T(elem);
  160.     }
  161.  
  162.     // Вызывает деструктор объекта по адресу buf
  163.     static void Destroy(T* buf) noexcept {
  164.         buf->~T();
  165.     }
  166.  
  167.     RawMemory<T> data_;
  168.     size_t size_ = 0;
  169. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement