Advertisement
chevengur

СПРИНТ № 8 | Семантика перемещения | Урок 8: Move-семантика для вектора

Aug 1st, 2024 (edited)
475
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.05 KB | None | 0 0
  1. array_ptr.h
  2.  
  3.  
  4. #include <cassert>
  5. #include <cstdlib>
  6.  
  7. template <typename Type>
  8. class ArrayPtr {
  9. public:
  10.     ArrayPtr() = default;
  11.  
  12.     explicit ArrayPtr(size_t size) {
  13.         (size == 0) ? raw_ptr_ = nullptr : raw_ptr_ = new Type[size];
  14.     }
  15.  
  16.     explicit ArrayPtr(Type* raw_ptr) noexcept {
  17.         if (raw_ptr) raw_ptr_ = raw_ptr;
  18.     }
  19.  
  20.     ArrayPtr(const ArrayPtr&) = delete;
  21.     ArrayPtr& operator=(const ArrayPtr&) = delete;
  22.  
  23.     ArrayPtr(ArrayPtr&& other)
  24.     {
  25.         raw_ptr_ = other.raw_ptr_;
  26.         other.raw_ptr_ = nullptr;
  27.     }
  28.  
  29.     ~ArrayPtr() {
  30.         delete[] raw_ptr_;
  31.     }
  32.  
  33.     [[nodiscard]] Type* Release() noexcept {
  34.         Type* currentarr = raw_ptr_;
  35.         raw_ptr_ = nullptr;
  36.         return currentarr;
  37.     }
  38.  
  39.     Type& operator[](size_t index) noexcept {
  40.         return raw_ptr_[index];
  41.     }
  42.  
  43.     const Type& operator[](size_t index) const noexcept {
  44.         return raw_ptr_[index];
  45.     }
  46.  
  47.     explicit operator bool() const {
  48.         return (raw_ptr_) ? true : false;
  49.     }
  50.  
  51.     Type* Get() const noexcept {
  52.         return raw_ptr_;
  53.     }
  54.  
  55.     void swap(ArrayPtr& other) noexcept {
  56.         Type* temp = other.raw_ptr_;
  57.         other.raw_ptr_ = raw_ptr_;
  58.         raw_ptr_ = temp;
  59.     }
  60.  
  61. private:
  62.     Type* raw_ptr_ = nullptr;
  63. };
  64.  
  65. =======================================================================================================================================
  66.  
  67.  
  68. simple_vector.h
  69.  
  70.  
  71. #pragma once
  72.  
  73. #include <cassert>
  74. #include <initializer_list>
  75. #include <vector>
  76. #include <exception>
  77. #include <algorithm>
  78. #include <iostream>
  79. #include "array_ptr.h"
  80.  
  81. class ReserveProxyObj {
  82. public:
  83.     ReserveProxyObj(size_t capacity_to_reserve)
  84.         : capacity_(capacity_to_reserve) {}
  85.  
  86.     size_t GetCapacity() const {
  87.         return capacity_;
  88.     }
  89.  
  90. private:
  91.     size_t capacity_;
  92. };
  93.  
  94. ReserveProxyObj Reserve(size_t capacity_to_reserve) {
  95.     return ReserveProxyObj(capacity_to_reserve);
  96. };
  97.  
  98. template <typename Type>
  99. class SimpleVector {
  100. public:
  101.     using Iterator = Type*;
  102.     using ConstIterator = const Type*;
  103.  
  104.     SimpleVector() noexcept = default;
  105.  
  106.     // Создаёт вектор из size элементов, инициализированных значением по умолчанию
  107.     explicit SimpleVector(size_t size) : size_(size), capacity_(size), ptr_(size) {
  108.         std::fill(begin(), end(), 0);
  109.     }
  110.  
  111.     // Создаёт вектор из size элементов, инициализированных значением value
  112.     SimpleVector(size_t size, const Type& value) : size_(size), capacity_(size), ptr_(size) {
  113.         std::fill(begin(), end(), value);
  114.     }
  115.  
  116.     // Создаёт вектор из std::initializer_list
  117.     SimpleVector(std::initializer_list<Type> init) : size_(init.size()), capacity_(init.size()), ptr_(init.size())
  118.     {
  119.         size_t b = 0;
  120.         for (const auto& i : init)
  121.         {
  122.             ptr_[b] = i;
  123.             ++b;
  124.         }
  125.     }
  126.  
  127.     SimpleVector(const SimpleVector& other): size_(other.size_), capacity_(other.capacity_), ptr_(other.size_){
  128.         std::copy(other.begin(), other.end(), begin());
  129.     }
  130.  
  131.     SimpleVector& operator=(const SimpleVector& rhs) {
  132.         SimpleVector copy{ rhs };
  133.         swap(copy);
  134.         return *this;
  135.     }
  136.  
  137.     SimpleVector(SimpleVector&& other)
  138.     {
  139.         swap(other);
  140.     }
  141.  
  142.     SimpleVector& operator=(SimpleVector&& other)
  143.     {
  144.         delete[] ptr_.Release();
  145.         ArrayPtr<Type> array_ptr(other.size_);
  146.         std::move(other.begin(), other.end(), array_ptr.Get());
  147.         ptr_.swap(array_ptr);
  148.         size_ = other.size_;
  149.         capacity_ = other.capacity_;
  150.         return *this;
  151.     }
  152.  
  153.     SimpleVector(ReserveProxyObj new_capacity)
  154.     {
  155.         Reserve(new_capacity.GetCapacity());
  156.     }
  157.  
  158.     void Reserve(size_t new_capacity)
  159.     {
  160.         if(new_capacity > capacity_)
  161.         {
  162.             auto new_vec = ArrayPtr<Type>(new_capacity);
  163.             for (size_t i = 0; i < capacity_; ++i)
  164.             {
  165.                 new_vec[i] = ptr_[i];
  166.             }
  167.             ptr_.swap(new_vec);
  168.             capacity_ = new_capacity;
  169.         }
  170.     }
  171.  
  172.     ~SimpleVector() {}
  173.  
  174.     // Возвращает количество элементов в массиве
  175.     size_t GetSize() const noexcept {
  176.         return size_;
  177.     }
  178.  
  179.     // Возвращает вместимость массива
  180.     size_t GetCapacity() const noexcept {
  181.         return capacity_;
  182.     }
  183.  
  184.     // Сообщает, пустой ли массив
  185.     bool IsEmpty() const noexcept {
  186.         return size_ == 0;
  187.     }
  188.  
  189.     // Возвращает ссылку на элемент с индексом index
  190.     Type& operator[](size_t index) noexcept {
  191.         return ptr_[index];
  192.     }
  193.  
  194.     // Возвращает константную ссылку на элемент с индексом index
  195.     const Type& operator[](size_t index) const noexcept {
  196.  
  197.         return ptr_[index];
  198.     }
  199.  
  200.     // Возвращает константную ссылку на элемент с индексом index
  201.     // Выбрасывает исключение std::out_of_range, если index >= size
  202.     Type& At(size_t index) {
  203.         if (index >= size_)
  204.             throw std::out_of_range("out of range");
  205.         return ptr_[index];
  206.     }
  207.  
  208.     // Возвращает константную ссылку на элемент с индексом index
  209.     // Выбрасывает исключение std::out_of_range, если index >= size
  210.     const Type& At(size_t index) const {
  211.         if (index > size_)
  212.             throw std::out_of_range("out of range");
  213.         return ptr_[index];
  214.     }
  215.  
  216.     // Обнуляет размер массива, не изменяя его вместимость
  217.     void Clear() noexcept {
  218.         size_ = 0;
  219.     }
  220.  
  221.     // Изменяет размер массива.
  222.     // При увеличении размера новые элементы получают значение по умолчанию для типа Type
  223.     void Resize(size_t new_size) {
  224.         if (new_size > capacity_) {
  225.             auto new_array = ArrayPtr<Type>(new_size);
  226.             for (size_t i = 0; i < size_; ++i) {
  227.                 new_array[i] = std::move(ptr_[i]);
  228.             }
  229.             ptr_.swap(new_array);
  230.             capacity_ = new_size;
  231.         }
  232.         for (size_t i = size_; i < new_size; ++i) {
  233.             ptr_[i] = Type();
  234.         }
  235.         size_ = new_size;
  236.     }
  237.  
  238.     // Возвращает итератор на начало массива
  239.     // Для пустого массива может быть равен (или не равен) nullptr
  240.     Iterator begin() noexcept {
  241.         return ptr_.Get();
  242.         // Напишите тело самостоятельно
  243.     }
  244.  
  245.     // Возвращает итератор на элемент, следующий за последним
  246.     // Для пустого массива может быть равен (или не равен) nullptr
  247.     Iterator end() noexcept {
  248.         return ptr_.Get() + size_;
  249.     }
  250.  
  251.     // Возвращает константный итератор на начало массива
  252.     // Для пустого массива может быть равен (или не равен) nullptr
  253.     ConstIterator begin() const noexcept {
  254.         return ptr_.Get();
  255.     }
  256.  
  257.     // Возвращает итератор на элемент, следующий за последним
  258.     // Для пустого массива может быть равен (или не равен) nullptr
  259.     ConstIterator end() const noexcept {
  260.         return ptr_.Get() + size_;
  261.     }
  262.  
  263.     // Возвращает константный итератор на начало массива
  264.     // Для пустого массива может быть равен (или не равен) nullptr
  265.     ConstIterator cbegin() const noexcept {
  266.         return ptr_.Get();
  267.     }
  268.  
  269.     // Возвращает итератор на элемент, следующий за последним
  270.     // Для пустого массива может быть равен (или не равен) nullptr
  271.     ConstIterator cend() const noexcept {
  272.         return ptr_.Get() + size_;
  273.     }
  274.  
  275.     // Добавляет элемент в конец вектора
  276.     // При нехватке места увеличивает вдвое вместимость вектора
  277.     void PushBack(Type&& item) {
  278.        if(size_ == capacity_)
  279.        {
  280.             auto new_capacity = (capacity_ == 0) ? 1 : capacity_ * 2;
  281.             auto new_vector = ArrayPtr<Type>(new_capacity);
  282.             for (size_t i = 0; i < size_; ++i)
  283.             {
  284.                 new_vector[i] = std::move(ptr_[i]);
  285.             }
  286.             ptr_.swap(new_vector);
  287.             capacity_ = new_capacity;
  288.        }
  289.        ptr_[size_] = std::move(item);
  290.        ++size_;
  291.     }
  292.  
  293.     // Вставляет значение value в позицию pos.
  294.     // Возвращает итератор на вставленное значение
  295.     // Если перед вставкой значения вектор был заполнен полностью,
  296.     // вместимость вектора должна увеличиться вдвое, а для вектора вместимостью 0 стать равной 1
  297.      Iterator Insert(ConstIterator pos, Type&& value) {
  298.         size_t index = pos - begin();
  299.         if(index > capacity_)
  300.         {
  301.             std::out_of_range("exit of out_of_range");
  302.         }
  303.         if(size_ == capacity_)
  304.         {
  305.             auto new_capacity = (capacity_ == 0) ? 1 : capacity_ * 2;
  306.             auto new_vector = ArrayPtr<Type>(new_capacity);
  307.             std::move(begin(), begin()+index, new_vector.Get());
  308.             new_vector[index] = std::move(value);
  309.             std::move(begin()+index, end(), new_vector.Get()+index+1);
  310.             ptr_.swap(new_vector);
  311.             capacity_ = new_capacity;
  312.         }
  313.         else{
  314.             std::move_backward(begin()+index, end(), end()+1);
  315.             ptr_[index] = std::move(value);
  316.         }
  317.         ++size_;
  318.         return Iterator(ptr_.Get() + index);
  319.     }
  320.  
  321.     // "Удаляет" последний элемент вектора. Вектор не должен быть пустым
  322.     void PopBack() noexcept {
  323.         if(size_) --size_;
  324.     }
  325.  
  326.     // Удаляет элемент вектора в указанной позиции
  327.     Iterator Erase(ConstIterator pos) {
  328.         auto index = pos-begin();
  329.        
  330.         if(size_)
  331.         {
  332.             auto new_vector = ArrayPtr<Type>(capacity_);
  333.             std::move(begin(), begin()+index, new_vector.Get());
  334.            
  335.             std::move(begin() + index+1, end(), new_vector.Get()+index);
  336.             --size_;
  337.             ptr_.swap(new_vector);
  338.         }
  339.         return Iterator(begin() + index);
  340.     }
  341.  
  342.     // Обменивает значение с другим вектором
  343.     void swap(SimpleVector& other) noexcept {
  344.         std::swap(size_, other.size_);
  345.         std::swap(capacity_, other.capacity_);
  346.         ptr_.swap(other.ptr_);
  347.     }
  348. private:
  349.     size_t size_ = 0;
  350.     size_t capacity_ = 0;
  351.     ArrayPtr<Type> ptr_;
  352. };
  353.  
  354. template <typename Type>
  355. inline bool operator==(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  356.     return std::equal(lhs.begin(), lhs.end(), rhs.begin());
  357. }
  358.  
  359. template <typename Type>
  360. inline bool operator!=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  361.     return !(rhs==lhs);
  362. }
  363.  
  364. template <typename Type>
  365. inline bool operator<(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  366.     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  367.    
  368. }
  369.  
  370. template <typename Type>
  371. inline bool operator<=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  372.     // Заглушка. Напишите тело самостоятельно
  373.     return (lhs<rhs) || (lhs==rhs);
  374. }
  375.  
  376. template <typename Type>
  377. inline bool operator>(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  378.     return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
  379. }
  380.  
  381. template <typename Type>
  382. inline bool operator>=(const SimpleVector<Type>& lhs, const SimpleVector<Type>& rhs) {
  383.     // Заглушка. Напишите тело самостоятельно
  384.     return (lhs>rhs) || (lhs==rhs);
  385. }
  386.  
  387.  
  388. =======================================================================================================================================
  389.  
  390.  
  391. main.cpp
  392.  
  393.  
  394. #include "simple_vector.h"
  395.  
  396. #include <cassert>
  397. #include <utility>
  398. #include <iostream>
  399. #include <numeric>
  400. #include <utility>
  401. #include <vector>
  402.  
  403. using namespace std;
  404.  
  405. class X {
  406. public:
  407.     X()
  408.         : X(5) {
  409.     }
  410.     X(size_t num)
  411.         : x_(num) {
  412.     }
  413.     X(const X& other) = delete;
  414.     X& operator=(const X& other) = delete;
  415.     X(X&& other) {
  416.         x_ = exchange(other.x_, 0);
  417.     }
  418.     X& operator=(X&& other) {
  419.         x_ = exchange(other.x_, 0);
  420.         return *this;
  421.     }
  422.     size_t GetX() const {
  423.         return x_;
  424.     }
  425.  
  426. private:
  427.     size_t x_;
  428. };
  429.  
  430. SimpleVector<int> GenerateVector(size_t size) {
  431.     SimpleVector<int> v(size);
  432.     iota(v.begin(), v.end(), 1);
  433.     return v;
  434. }
  435.  
  436. void TestTemporaryObjConstructor() {
  437.     const size_t size = 1000000;
  438.     cout << "Test with temporary object, copy elision" << endl;
  439.     SimpleVector<int> moved_vector(GenerateVector(size));
  440.     assert(moved_vector.GetSize() == size);
  441.     cout << "Done!" << endl << endl;
  442. }
  443.  
  444. void TestTemporaryObjOperator() {
  445.     const size_t size = 1000000;
  446.     cout << "Test with temporary object, operator=" << endl;
  447.     SimpleVector<int> moved_vector;
  448.     assert(moved_vector.GetSize() == 0);
  449.     moved_vector = GenerateVector(size);
  450.     assert(moved_vector.GetSize() == size);
  451.     cout << "Done!" << endl << endl;
  452. }
  453.  
  454. void TestNamedMoveConstructor() {
  455.     const size_t size = 1000000;
  456.     cout << "Test with named object, move constructor" << endl;
  457.     SimpleVector<int> vector_to_move(GenerateVector(size));
  458.     assert(vector_to_move.GetSize() == size);
  459.  
  460.     SimpleVector<int> moved_vector(move(vector_to_move));
  461.     assert(moved_vector.GetSize() == size);
  462.     assert(vector_to_move.GetSize() == 0);
  463.     cout << "Done!" << endl << endl;
  464. }
  465.  
  466. void TestNamedMoveOperator() {
  467.     const size_t size = 1000000;
  468.     cout << "Test with named object, operator=" << endl;
  469.     SimpleVector<int> vector_to_move(GenerateVector(size));
  470.     assert(vector_to_move.GetSize() == size);
  471.  
  472.     SimpleVector<int> moved_vector = move(vector_to_move);
  473.     assert(moved_vector.GetSize() == size);
  474.     assert(vector_to_move.GetSize() == 0);
  475.     cout << "Done!" << endl << endl;
  476. }
  477.  
  478. void TestNoncopiableMoveConstructor() {
  479.     const size_t size = 5;
  480.     cout << "Test noncopiable object, move constructor" << endl;
  481.     SimpleVector<X> vector_to_move;
  482.     for (size_t i = 0; i < size; ++i) {
  483.         vector_to_move.PushBack(X(i));
  484.     }
  485.  
  486.     SimpleVector<X> moved_vector = move(vector_to_move);
  487.     assert(moved_vector.GetSize() == size);
  488.     assert(vector_to_move.GetSize() == 0);
  489.  
  490.     for (size_t i = 0; i < size; ++i) {
  491.         assert(moved_vector[i].GetX() == i);
  492.     }
  493.     cout << "Done!" << endl << endl;
  494. }
  495.  
  496. void TestNoncopiablePushBack() {
  497.     const size_t size = 5;
  498.     cout << "Test noncopiable push back" << endl;
  499.     SimpleVector<X> v;
  500.     for (size_t i = 0; i < size; ++i) {
  501.         v.PushBack(X(i));
  502.     }
  503.  
  504.     assert(v.GetSize() == size);
  505.  
  506.     for (size_t i = 0; i < size; ++i) {
  507.         assert(v[i].GetX() == i);
  508.     }
  509.     cout << "Done!" << endl << endl;
  510. }
  511.  
  512. void TestNoncopiableInsert() {
  513.     const size_t size = 5;
  514.     cout << "Test noncopiable insert" << endl;
  515.     SimpleVector<X> v;
  516.     for (size_t i = 0; i < size; ++i) {
  517.         v.PushBack(X(i));
  518.     }
  519.  
  520.     // в начало
  521.     v.Insert(v.begin(), X(size + 1));
  522.     assert(v.GetSize() == size + 1);
  523.     assert(v.begin()->GetX() == size + 1);
  524.     // в конец
  525.     v.Insert(v.end(), X(size + 2));
  526.     assert(v.GetSize() == size + 2);
  527.     assert((v.end() - 1)->GetX() == size + 2);
  528.     // в середину
  529.     v.Insert(v.begin() + 3, X(size + 3));
  530.     assert(v.GetSize() == size + 3);
  531.     assert((v.begin() + 3)->GetX() == size + 3);
  532.     cout << "Done!" << endl << endl;
  533. }
  534.  
  535. void TestNoncopiableErase() {
  536.     const size_t size = 3;
  537.     cout << "Test noncopiable erase" << endl;
  538.     SimpleVector<X> v;
  539.     for (size_t i = 0; i < size; ++i) {
  540.         v.PushBack(X(i));
  541.     }
  542.  
  543.     auto it = v.Erase(v.begin());
  544.     assert(it->GetX() == 1);
  545.     cout << "Done!" << endl << endl;
  546. }
  547.  
  548. int main() {
  549.      TestTemporaryObjConstructor();
  550.      TestTemporaryObjOperator();
  551.      TestNamedMoveConstructor();
  552.      TestNamedMoveOperator();
  553.      TestNoncopiableMoveConstructor();
  554.      TestNoncopiablePushBack();
  555.      TestNoncopiableInsert();
  556.      TestNoncopiableErase();
  557.  
  558.     return 0;
  559. }
  560.  
  561.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement