shushus

Спринт 14. Размещающий оператор new.

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