Advertisement
kutuzzzov

Урок 3 размещающий оператор new

Jul 17th, 2023
1,161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.68 KB | None | 0 0
  1. // main.cpp
  2.  
  3. #include "optional.h"
  4.  
  5. #include <cassert>
  6.  
  7. struct C {
  8.     C() noexcept {
  9.         ++def_ctor;
  10.     }
  11.     C(const C& /*other*/) noexcept {
  12.         ++copy_ctor;
  13.     }
  14.     C(C&& /*other*/) noexcept {
  15.         ++move_ctor;
  16.     }
  17.     C& operator=(const C& other) noexcept {
  18.         if (this != &other) {
  19.             ++copy_assign;
  20.         }
  21.         return *this;
  22.     }
  23.     C& operator=(C&& /*other*/) noexcept {
  24.         ++move_assign;
  25.         return *this;
  26.     }
  27.     ~C() {
  28.         ++dtor;
  29.     }
  30.  
  31.     static size_t InstanceCount() {
  32.         return def_ctor + copy_ctor + move_ctor - dtor;
  33.     }
  34.  
  35.     static void Reset() {
  36.         def_ctor = 0;
  37.         copy_ctor = 0;
  38.         move_ctor = 0;
  39.         copy_assign = 0;
  40.         move_assign = 0;
  41.         dtor = 0;
  42.     }
  43.  
  44.     inline static size_t def_ctor = 0;
  45.     inline static size_t copy_ctor = 0;
  46.     inline static size_t move_ctor = 0;
  47.     inline static size_t copy_assign = 0;
  48.     inline static size_t move_assign = 0;
  49.     inline static size_t dtor = 0;
  50. };
  51.  
  52. void TestInitialization() {
  53.     C::Reset();
  54.     {
  55.         Optional<C> o;
  56.         assert(!o.HasValue());
  57.         assert(C::InstanceCount() == 0);
  58.     }
  59.     assert(C::InstanceCount() == 0);
  60.  
  61.     C::Reset();
  62.     {
  63.         C c;
  64.         Optional<C> o(c);
  65.         assert(o.HasValue());
  66.         assert(C::def_ctor == 1 && C::copy_ctor == 1);
  67.         assert(C::InstanceCount() == 2);
  68.     }
  69.     assert(C::InstanceCount() == 0);
  70.  
  71.     C::Reset();
  72.     {
  73.         C c;
  74.         Optional<C> o(std::move(c));
  75.         assert(o.HasValue());
  76.         assert(C::def_ctor == 1 && C::move_ctor == 1 && C::copy_ctor == 0 && C::copy_assign == 0
  77.                && C::move_assign == 0);
  78.         assert(C::InstanceCount() == 2);
  79.     }
  80.     assert(C::InstanceCount() == 0);
  81.  
  82.     C::Reset();
  83.     {
  84.         C c;
  85.         Optional<C> o1(c);
  86.         const Optional<C> o2(o1);
  87.         assert(o1.HasValue());
  88.         assert(o2.HasValue());
  89.         assert(C::def_ctor == 1 && C::move_ctor == 0 && C::copy_ctor == 2 && C::copy_assign == 0
  90.                && C::move_assign == 0);
  91.         assert(C::InstanceCount() == 3);
  92.     }
  93.     assert(C::InstanceCount() == 0);
  94.  
  95.     C::Reset();
  96.     {
  97.         C c;
  98.         Optional<C> o1(c);
  99.         const Optional<C> o2(std::move(o1));
  100.         assert(C::def_ctor == 1 && C::copy_ctor == 1 && C::move_ctor == 1 && C::copy_assign == 0
  101.                && C::move_assign == 0);
  102.         assert(C::InstanceCount() == 3);
  103.     }
  104.     assert(C::InstanceCount() == 0);
  105. }
  106.  
  107. void TestAssignment() {
  108.     Optional<C> o1;
  109.     Optional<C> o2;
  110.     {  // Assign a value to empty
  111.         C::Reset();
  112.         C c;
  113.         o1 = c;
  114.         assert(C::def_ctor == 1 && C::copy_ctor == 1 && C::dtor == 0);
  115.     }
  116.     {  // Assign a non-empty to empty
  117.         C::Reset();
  118.         o2 = o1;
  119.         assert(C::copy_ctor == 1 && C::copy_assign == 0 && C::dtor == 0);
  120.     }
  121.     {  // Assign non empty to non-empty
  122.         C::Reset();
  123.         o2 = o1;
  124.         assert(C::copy_ctor == 0 && C::copy_assign == 1 && C::dtor == 0);
  125.     }
  126.     {  // Assign empty to non empty
  127.         C::Reset();
  128.         Optional<C> empty;
  129.         o1 = empty;
  130.         assert(C::copy_ctor == 0 && C::dtor == 1);
  131.         assert(!o1.HasValue());
  132.     }
  133. }
  134.  
  135. void TestMoveAssignment() {
  136.     {  // Assign a value to empty
  137.         Optional<C> o1;
  138.         C::Reset();
  139.         C c;
  140.         o1 = std::move(c);
  141.         assert(C::def_ctor == 1 && C::move_ctor == 1 && C::dtor == 0);
  142.     }
  143.     {  // Assign a non-empty to empty
  144.         Optional<C> o1;
  145.         Optional<C> o2{C{}};
  146.         C::Reset();
  147.         o1 = std::move(o2);
  148.         assert(C::move_ctor == 1 && C::move_assign == 0 && C::dtor == 0);
  149.     }
  150.     {  // Assign non empty to non-empty
  151.         Optional<C> o1{C{}};
  152.         Optional<C> o2{C{}};
  153.         C::Reset();
  154.         o2 = std::move(o1);
  155.         assert(C::copy_ctor == 0 && C::move_assign == 1 && C::dtor == 0);
  156.     }
  157.     {  // Assign empty to non empty
  158.         Optional<C> o1{C{}};
  159.         C::Reset();
  160.         Optional<C> empty;
  161.         o1 = std::move(empty);
  162.         assert(C::copy_ctor == 0 && C::move_ctor == 0 && C::move_assign == 0 && C::dtor == 1);
  163.         assert(!o1.HasValue());
  164.     }
  165. }
  166.  
  167. void TestValueAccess() {
  168.     using namespace std::literals;
  169.     {
  170.         Optional<std::string> o;
  171.         o = "hello"s;
  172.         assert(o.HasValue());
  173.         assert(o.Value() == "hello"s);
  174.         assert(&*o == &o.Value());
  175.         assert(o->length() == 5);
  176.     }
  177.     {
  178.         try {
  179.             Optional<int> o;
  180.             [[maybe_unused]] int v = o.Value();
  181.             assert(false);
  182.         } catch (const BadOptionalAccess& /*e*/) {
  183.         } catch (...) {
  184.             assert(false);
  185.         }
  186.     }
  187. }
  188.  
  189. void TestReset() {
  190.     C::Reset();
  191.     {
  192.         Optional<C> o{C()};
  193.         assert(o.HasValue());
  194.         o.Reset();
  195.         assert(!o.HasValue());
  196.     }
  197. }
  198.  
  199. int main() {
  200.     try {
  201.         TestInitialization();
  202.         TestAssignment();
  203.         TestMoveAssignment();
  204.         TestValueAccess();
  205.         TestReset();
  206.     } catch (...) {
  207.         assert(false);
  208.     }
  209. }
  210.  
  211. // optional.h
  212.  
  213. #include <stdexcept>
  214. #include <utility>
  215.  
  216. // Исключение этого типа должно генерироватся при обращении к пустому optional
  217. class BadOptionalAccess : public std::exception {
  218. public:
  219.     using exception::exception;
  220.  
  221.     virtual const char* what() const noexcept override {
  222.         return "Bad optional access";
  223.     }
  224. };
  225.  
  226. template <typename T>
  227. class Optional {
  228. public:
  229.     Optional() = default;
  230.     Optional(const T& value);
  231.     Optional(T&& value);
  232.     Optional(const Optional& other);
  233.     Optional(Optional&& other);
  234.  
  235.     Optional& operator=(const T& value);
  236.     Optional& operator=(T&& rhs);
  237.     Optional& operator=(const Optional& rhs);
  238.     Optional& operator=(Optional&& rhs);
  239.  
  240.     ~Optional();
  241.  
  242.     bool HasValue() const;
  243.  
  244.     // Операторы * и -> не должны делать никаких проверок на пустоту Optional.
  245.     // Эти проверки остаются на совести программиста
  246.     T& operator*();
  247.     const T& operator*() const;
  248.     T* operator->();
  249.     const T* operator->() const;
  250.  
  251.     // Метод Value() генерирует исключение BadOptionalAccess, если Optional пуст
  252.     T& Value();
  253.     const T& Value() const;
  254.  
  255.     void Reset();
  256.  
  257. private:
  258.     // alignas нужен для правильного выравнивания блока памяти
  259.     alignas(T) char data_[sizeof(T)];
  260.     T* ptr_ = nullptr;
  261.     bool is_initialized_ = false;
  262. };
  263.  
  264. template <typename T>
  265. Optional<T>::Optional(const T& value)
  266.     : is_initialized_(true) {
  267.     ptr_ = new(&data_[0]) T(value);
  268. }
  269.  
  270. template <typename T>
  271. Optional<T>::Optional(T&& value)
  272.     : is_initialized_(true) {
  273.     ptr_ = new(&data_[0]) T(std::move(value));
  274. }
  275.  
  276. template <typename T>
  277. Optional<T>::Optional(const Optional& other)
  278.     : is_initialized_(other.is_initialized_) {
  279.     if (is_initialized_) {
  280.         ptr_ = new(&data_[0]) T(other.Value());
  281.     }
  282. }
  283.  
  284. template <typename T>
  285. Optional<T>::Optional(Optional&& other)
  286.     : is_initialized_(std::move(other.is_initialized_)) {
  287.     if (is_initialized_) {
  288.         ptr_ = new(&data_[0]) T(std::move(other.Value()));
  289.     }
  290. }
  291.  
  292. template <typename T>
  293. Optional<T>::~Optional() {
  294.     Reset();
  295. }
  296.  
  297. template <typename T>
  298. Optional<T>& Optional<T>::operator=(const T& value) {
  299.     if (!is_initialized_) {
  300.         ptr_ = new(&data_[0]) T(value);
  301.         is_initialized_ = true;
  302.     }
  303.     else {
  304.         *ptr_ = value;
  305.     }
  306.     return *this;
  307. }
  308.  
  309. template <typename T>
  310. Optional<T>& Optional<T>::operator=(T&& rhs) {
  311.     if (!is_initialized_) {
  312.         ptr_ = new(&data_[0]) T(std::move(rhs));
  313.         is_initialized_ = true;
  314.     }
  315.     else {
  316.         *ptr_ = std::move(rhs);
  317.     }
  318.     return *this;
  319. }
  320.  
  321. template <typename T>
  322. Optional<T>& Optional<T>::operator=(const Optional& rhs) {
  323.     if (!is_initialized_) {
  324.         if (rhs.is_initialized_) {
  325.             ptr_ = new(&data_[0]) T(rhs.Value());
  326.             is_initialized_ = rhs.is_initialized_;
  327.         }
  328.     }
  329.     else {
  330.         if (rhs.is_initialized_) {
  331.             *ptr_ = rhs.Value();
  332.         }
  333.         else {
  334.             Reset();
  335.         }
  336.     }
  337.     return *this;
  338. }
  339.  
  340. template <typename T>
  341. Optional<T>& Optional<T>::operator=(Optional&& rhs) {
  342.     if (!is_initialized_) {
  343.         if (rhs.is_initialized_) {
  344.             ptr_ = new(&data_[0]) T(std::move(rhs.Value()));
  345.             is_initialized_ = std::move(rhs.is_initialized_);
  346.         }
  347.     }
  348.     else {
  349.         if (rhs.is_initialized_) {
  350.             *ptr_ = std::move(rhs.Value());
  351.         }
  352.         else {
  353.             Reset();
  354.         }
  355.     }
  356.     return *this;
  357. }
  358.  
  359. template <typename T>
  360. bool Optional<T>::HasValue() const {
  361.     return is_initialized_;
  362. }
  363.  
  364. template <typename T>
  365. T& Optional<T>::operator*() {
  366.     return *ptr_;
  367. }
  368.  
  369. template <typename T>
  370. const T& Optional<T>::operator*() const {
  371.     return *ptr_;
  372. }
  373.  
  374. template <typename T>
  375. T* Optional<T>::operator->() {
  376.     return ptr_;
  377. }
  378.  
  379. template <typename T>
  380. const T* Optional<T>::operator->() const {
  381.     return ptr_;
  382. }
  383.  
  384. template <typename T>
  385. T& Optional<T>::Value() {
  386.     if (!is_initialized_) {
  387.         throw BadOptionalAccess();
  388.     }
  389.     return *ptr_;
  390. }
  391.  
  392. template <typename T>
  393. const T& Optional<T>::Value() const {
  394.     if (!is_initialized_) {
  395.         throw BadOptionalAccess();
  396.     }
  397.     return *ptr_;
  398. }
  399.  
  400. template <typename T>
  401. void Optional<T>::Reset() {
  402.     if (is_initialized_) {
  403.         ptr_->~T();
  404.         ptr_ = nullptr;
  405.     }
  406.     is_initialized_ = false;
  407. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement