shushus

Спринт 14. Перегрузка методов по rvalue-ссылке.

May 5th, 2023
575
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.03 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.     T&& Value() && {if (!is_initialized_) {throw BadOptionalAccess();} else {return std::move(*buff_);}}
  58.  
  59.     void Reset() {is_initialized_ ? (is_initialized_ = false, buff_->~T()) : void();}
  60.    
  61.     template <typename ... Args>
  62.     void Emplace(Args&& ...args);
  63.  
  64.     Optional& operator=(const T& item) {
  65.        
  66.         HasValue() ? (void)(*buff_ = item ) : (void)(buff_ = new (&data_[0]) T(item), is_initialized_ = true);
  67.  
  68.         return *this;
  69.     }
  70.                                            
  71.     Optional& operator=(T&& item) {
  72.        
  73.         HasValue() ? (void)(*buff_ = std::forward<T>(item))
  74.         : (void)(buff_ = new (&data_[0]) T(std::forward<T>(item)), is_initialized_ = true);
  75.  
  76.         return *this;
  77.     }
  78.                                            
  79.     Optional& operator=(const Optional& other) {
  80.        
  81.         (!other.HasValue() && HasValue()) ? Reset() :
  82.         (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(other.Value()), is_initialized_ = true) :
  83.         (other.HasValue() && HasValue()) ? (void)(*buff_ = other.Value(), is_initialized_ = true) : void();
  84.        
  85.         return *this;
  86.     }
  87.    
  88.     Optional& operator=(Optional&& other) noexcept {
  89.        
  90.         (!other.HasValue() && HasValue()) ? Reset() :
  91.         (other.HasValue() && !HasValue()) ? (void)(buff_ = new (&data_[0]) T(std::forward<T>(other.Value())), is_initialized_ = true) :
  92.         (other.HasValue() && HasValue()) ? (void)(*buff_ = std::forward<T>(other.Value()), is_initialized_ = true) : void();
  93.  
  94.         return *this;
  95.     }
  96.  
  97.     T& operator*() & {return Value();}
  98.     const T& operator*() const & {return Value();}
  99.     T&& operator*() && {return std::move(Value());}
  100.     T* operator->() {return &Value();}
  101.     const T* operator->() const {return &Value();}
  102.  
  103. private:
  104.     T* buff_ = nullptr;
  105.    
  106.     alignas(T) char data_[sizeof(T)]{};
  107.     bool is_initialized_ = false;
  108. };
  109.  
  110. template <typename T>
  111. template <typename ... Args>
  112. void Optional<T>::Emplace(Args&& ...args) {
  113.  
  114.     if (is_initialized_) {buff_->~T();}
  115.  
  116.     buff_ = new (&data_[0]) T(std::forward<Args>(args)...);
  117.     is_initialized_ = true;
  118. }
  119. -----------------------------------------------------------------------
  120. main.cpp
  121. -----------------------------------------------------------------------
  122. #include "optional.h"
  123.  
  124. #include <cassert>
  125. #include <memory>
  126.  
  127. struct C {
  128.     C() noexcept {++def_ctor;}
  129.     C(const C& /*other*/) noexcept {++copy_ctor; }
  130.     C(C&& /*other*/) noexcept {++move_ctor;}
  131.    
  132.     C& operator=(const C& other) noexcept {
  133.         if (this != &other) {
  134.             ++copy_assign;
  135.         }
  136.        
  137.         return *this;
  138.     }
  139.    
  140.     C& operator=(C&& /*other*/) noexcept {
  141.         ++move_assign;
  142.         return *this;
  143.     }
  144.    
  145.     ~C() {++dtor;}
  146.    
  147.     void Update() const& {++const_lvalue_call_count;}
  148.     void Update() & {++lvalue_call_count;}
  149.     void Update() && {++rvalue_call_count;}
  150.  
  151.     static size_t InstanceCount() {return def_ctor + copy_ctor + move_ctor - dtor;}
  152.  
  153.     static void Reset() {
  154.         def_ctor = 0;
  155.         copy_ctor = 0;
  156.         move_ctor = 0;
  157.         copy_assign = 0;
  158.         move_assign = 0;
  159.         dtor = 0;
  160.         lvalue_call_count = 0;
  161.         rvalue_call_count = 0;
  162.         const_lvalue_call_count = 0;
  163.     }
  164.  
  165.     inline static size_t def_ctor = 0;
  166.     inline static size_t copy_ctor = 0;
  167.     inline static size_t move_ctor = 0;
  168.     inline static size_t copy_assign = 0;
  169.     inline static size_t move_assign = 0;
  170.     inline static size_t dtor = 0;
  171.     inline static size_t lvalue_call_count = 0;
  172.     inline static size_t rvalue_call_count = 0;
  173.     inline static size_t const_lvalue_call_count = 0;
  174. };
  175.  
  176. void TestInitialization() {
  177.     C::Reset();
  178.     {
  179.         Optional<C> o;
  180.         assert(!o.HasValue());
  181.         assert(C::InstanceCount() == 0);
  182.     }
  183.     assert(C::InstanceCount() == 0);
  184.  
  185.     C::Reset();
  186.     {
  187.         C c;
  188.         Optional<C> o(c);
  189.         assert(o.HasValue());
  190.         assert(C::def_ctor == 1
  191.                && C::copy_ctor == 1);
  192.        
  193.         assert(C::InstanceCount() == 2);
  194.     }
  195.     assert(C::InstanceCount() == 0);
  196.  
  197.     C::Reset();
  198.     {
  199.         C c;
  200.         Optional<C> o(std::move(c));
  201.         assert(o.HasValue());
  202.        
  203.         assert(C::def_ctor == 1
  204.                && C::move_ctor == 1
  205.                && C::copy_ctor == 0
  206.                && C::copy_assign == 0
  207.                && C::move_assign == 0);
  208.        
  209.         assert(C::InstanceCount() == 2);
  210.     }
  211.     assert(C::InstanceCount() == 0);
  212.  
  213.     C::Reset();
  214.     {
  215.         C c;
  216.         Optional<C> o1(c);
  217.         const Optional<C> o2(o1);
  218.         assert(o1.HasValue());
  219.         assert(o2.HasValue());
  220.        
  221.         assert(C::def_ctor == 1
  222.                && C::move_ctor == 0
  223.                && C::copy_ctor == 2
  224.                && C::copy_assign == 0
  225.                && C::move_assign == 0);
  226.        
  227.         assert(C::InstanceCount() == 3);
  228.     }
  229.     assert(C::InstanceCount() == 0);
  230.  
  231.     C::Reset();
  232.     {
  233.         C c;
  234.         Optional<C> o1(c);
  235.         const Optional<C> o2(std::move(o1));
  236.         assert(C::def_ctor == 1
  237.                && C::copy_ctor == 1
  238.                && C::move_ctor == 1
  239.                && C::copy_assign == 0
  240.                && C::move_assign == 0);
  241.        
  242.         assert(C::InstanceCount() == 3);
  243.     }
  244.     assert(C::InstanceCount() == 0);
  245. }
  246.  
  247. void TestAssignment() {
  248.     Optional<C> o1;
  249.     Optional<C> o2;
  250.    
  251.     {
  252.         C::Reset();
  253.         C c;
  254.         o1 = c;
  255.         assert(C::def_ctor == 1
  256.                && C::copy_ctor == 1
  257.                && C::dtor == 0);
  258.     }
  259.    
  260.     {
  261.         C::Reset();
  262.         o2 = o1;
  263.         assert(C::copy_ctor == 1
  264.                && C::copy_assign == 0
  265.                && C::dtor == 0);
  266.     }
  267.    
  268.     {
  269.         C::Reset();
  270.         o2 = o1;
  271.         assert(C::copy_ctor == 0
  272.                && C::copy_assign == 1
  273.                && C::dtor == 0);
  274.     }
  275.    
  276.     {
  277.         C::Reset();
  278.         Optional<C> empty;
  279.         o1 = empty;
  280.         assert(C::copy_ctor == 0
  281.                && C::dtor == 1);
  282.        
  283.         assert(!o1.HasValue());
  284.     }
  285. }
  286.  
  287. void TestMoveAssignment() {
  288.     {
  289.         Optional<C> o1;
  290.         C::Reset();
  291.         C c;
  292.         o1 = std::move(c);
  293.         assert(C::def_ctor == 1
  294.                && C::move_ctor == 1
  295.                && C::dtor == 0);
  296.     }
  297.    
  298.     {
  299.         Optional<C> o1;
  300.         Optional<C> o2{C{}};
  301.         C::Reset();
  302.         o1 = std::move(o2);
  303.         assert(C::move_ctor == 1
  304.                && C::move_assign == 0
  305.                && C::dtor == 0);
  306.     }
  307.    
  308.     {
  309.         Optional<C> o1{C{}};
  310.         Optional<C> o2{C{}};
  311.         C::Reset();
  312.         o2 = std::move(o1);
  313.         assert(C::copy_ctor == 0
  314.                && C::move_assign == 1
  315.                && C::dtor == 0);
  316.     }
  317.    
  318.     {
  319.         Optional<C> o1{C{}};
  320.         C::Reset();
  321.         Optional<C> empty;
  322.         o1 = std::move(empty);
  323.         assert(C::copy_ctor == 0
  324.                && C::move_ctor == 0
  325.                && C::move_assign == 0
  326.                && C::dtor == 1);
  327.        
  328.         assert(!o1.HasValue());
  329.     }
  330. }
  331.  
  332. void TestValueAccess() {
  333.     using namespace std::literals;
  334.    
  335.     {
  336.         Optional<std::string> o;
  337.         o = "hello"s;
  338.         assert(o.HasValue());
  339.         assert(o.Value() == "hello"s);
  340.         assert(&*o == &o.Value());
  341.         assert(o->length() == 5);
  342.     }
  343.    
  344.     {
  345.         try {
  346.             Optional<int> o;
  347.             [[maybe_unused]] int v = o.Value();
  348.             assert(false);
  349.            
  350.         } catch (const BadOptionalAccess& /*e*/) {
  351.            
  352.         } catch (...) {
  353.             assert(false);
  354.         }
  355.     }
  356.    
  357. }
  358.  
  359. void TestReset() {
  360.     C::Reset();
  361.     {
  362.         Optional<C> o{C()};
  363.         assert(o.HasValue());
  364.         o.Reset();
  365.         assert(!o.HasValue());
  366.     }
  367. }
  368.  
  369. void TestEmplace() {
  370.     struct S {
  371.        
  372.         S(int i, std::unique_ptr<int>&& p) : i(i)
  373.                                            , p(std::move(p)) {}
  374.         int i;
  375.         std::unique_ptr<int> p;
  376.     };
  377.  
  378.     Optional<S> o;
  379.     o.Emplace(1, std::make_unique<int>(2));
  380.    
  381.     assert(o.HasValue());
  382.     assert(o->i == 1);
  383.     assert(*(o->p) == 2);
  384.  
  385.     o.Emplace(3, std::make_unique<int>(4));
  386.    
  387.     assert(o.HasValue());
  388.     assert(o->i == 3);
  389.     assert(*(o->p) == 4);
  390. }
  391.  
  392. void TestRefQualifiedMethodOverloading() {
  393.    
  394.     {
  395.         C::Reset();
  396.         C val = *Optional<C>(C{});
  397.        
  398.         assert(C::copy_ctor == 0);
  399.         assert(C::move_ctor == 2);
  400.         assert(C::def_ctor == 1);
  401.         assert(C::copy_assign == 0);
  402.         assert(C::move_assign == 0);
  403.     }
  404.    
  405.     {
  406.         C::Reset();
  407.         C val = Optional<C>(C{}).Value();
  408.        
  409.         assert(C::copy_ctor == 0);
  410.         assert(C::move_ctor == 2);
  411.         assert(C::def_ctor == 1);
  412.         assert(C::copy_assign == 0);
  413.         assert(C::move_assign == 0);
  414.     }
  415.    
  416.     {
  417.         C::Reset();
  418.         Optional<C> opt(C{});
  419.         (*opt).Update();
  420.        
  421.         assert(C::lvalue_call_count == 1);
  422.         assert(C::rvalue_call_count == 0);
  423.        
  424.         (*std::move(opt)).Update();
  425.        
  426.         assert(C::lvalue_call_count == 1);
  427.         assert(C::rvalue_call_count == 1);
  428.     }
  429.    
  430.     {
  431.         C::Reset();
  432.         const Optional<C> opt(C{});
  433.         (*opt).Update();
  434.        
  435.         assert(C::const_lvalue_call_count == 1);
  436.     }
  437.    
  438.     {
  439.         C::Reset();
  440.         Optional<C> opt(C{});
  441.         opt.Value().Update();
  442.        
  443.         assert(C::lvalue_call_count == 1);
  444.         assert(C::rvalue_call_count == 0);
  445.        
  446.         std::move(opt).Value().Update();
  447.        
  448.         assert(C::lvalue_call_count == 1);
  449.     }
  450.    
  451.     {
  452.         C::Reset();
  453.         const Optional<C> opt(C{});
  454.         opt.Value().Update();
  455.        
  456.         assert(C::const_lvalue_call_count == 1);
  457.     }
  458. }
  459.  
  460. int main() {
  461.    
  462.     try {
  463.         TestInitialization();
  464.         TestAssignment();
  465.         TestMoveAssignment();
  466.         TestValueAccess();
  467.         TestReset();
  468.         TestEmplace();
  469.         TestRefQualifiedMethodOverloading();
  470.     } catch (...) {
  471.         assert(false);
  472.     }
  473.    
  474. }
Advertisement
Add Comment
Please, Sign In to add comment