Advertisement
35657

Untitled

Sep 18th, 2023
915
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.10 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <stdexcept>
  4. #include <utility>
  5.  
  6. // Исключение этого типа должно генерироватся при обращении к пустому optional
  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, typename... S>
  17. class Optional {
  18. public:
  19.     Optional() = default;
  20.  
  21.     Optional(const T& value) : ptr_(new (&data_[0]) T(value)), is_initialized_(true) {}
  22.  
  23.     Optional(T&& value) : ptr_(new (&data_[0]) T(std::move(value))), is_initialized_(true) {}
  24.  
  25.     Optional(const Optional& other) {
  26.         if (other.is_initialized_) {
  27.             ptr_ = new (&data_[0]) T(*other.ptr_);
  28.             is_initialized_ = true;
  29.         }
  30.     }
  31.  
  32.     Optional(const Optional&& other) {
  33.         if (other.is_initialized_) {
  34.             ptr_ = new (&data_[0]) T(std::move(*other.ptr_));
  35.             is_initialized_ = true;
  36.         }
  37.     }
  38.  
  39.     Optional& operator=(const T& value) {
  40.         if (!is_initialized_) {
  41.             ptr_ = new (&data_[0]) T(value);
  42.             is_initialized_ = true;
  43.             return *this;
  44.         }
  45.         *ptr_ = value;
  46.         return *this;
  47.     }
  48.  
  49.     Optional& operator=(T&& value) {
  50.         if (!is_initialized_) {
  51.             ptr_ = new (&data_[0]) T(std::move(value));
  52.             is_initialized_ = true;
  53.             return *this;
  54.         }
  55.         *ptr_ = std::move(value);
  56.         return *this;
  57.     }
  58.  
  59.     Optional& operator=(const Optional& rhs) {
  60.         if (!is_initialized_) {
  61.             if (!rhs.is_initialized_) {
  62.                 return *this;
  63.             }
  64.             ptr_ = new (&data_[0]) T(*rhs.ptr_);
  65.             is_initialized_ = true;
  66.             return *this;
  67.         }
  68.         if (!rhs.is_initialized_) {
  69.             ptr_->~T();
  70.             is_initialized_ = false;
  71.             return *this;
  72.         }
  73.         *ptr_ = *rhs.ptr_;
  74.         return *this;
  75.     }
  76.  
  77.     Optional& operator=(Optional&& rhs) {
  78.         if (!is_initialized_) {
  79.             if (!rhs.is_initialized_) {
  80.                 return *this;
  81.             }
  82.             ptr_ = new (&data_[0]) T(std::move(*rhs.ptr_));
  83.             is_initialized_ = true;
  84.             return *this;
  85.         }
  86.         if (!rhs.is_initialized_) {
  87.             ptr_->~T();
  88.             is_initialized_ = false;
  89.             return *this;
  90.         }
  91.         *ptr_ = std::move(*rhs.ptr_);
  92.         return *this;
  93.     }
  94.  
  95.     void Emplace(S&&... s) {
  96.         if (!is_initialized_) {
  97.             ptr_ = new (&data_[0]) T(std::forward<S>(s)...);
  98.             is_initialized_ = true;
  99.             return;
  100.         }
  101.         ptr_->~T();
  102.         ptr_ = new (&data_[0]) T(std::forward<S>(s)...);
  103.     }
  104.  
  105.  
  106.     ~Optional() {
  107.         if (is_initialized_) {
  108.             ptr_->~T();
  109.         }
  110.     }
  111.  
  112.     bool HasValue() const {
  113.         return is_initialized_;
  114.     }
  115.  
  116.     // Операторы * и -> не должны делать никаких проверок на пустоту Optional.
  117.     // Эти проверки остаются на совести программиста
  118.     T& operator*() {
  119.         return *ptr_;
  120.     }
  121.  
  122.     const T& operator*() const {
  123.         return *ptr_;
  124.     }
  125.  
  126.     T* operator->() {
  127.         return ptr_;
  128.     }
  129.  
  130.     const T* operator->() const {
  131.         return ptr_;
  132.     }
  133.  
  134.     // Метод Value() генерирует исключение BadOptionalAccess, если Optional пуст
  135.     T& Value() {
  136.         if (!is_initialized_) {
  137.             throw BadOptionalAccess();
  138.         }
  139.         return *ptr_;
  140.     }
  141.     const T& Value() const {
  142.         if (!is_initialized_) {
  143.             throw BadOptionalAccess();
  144.         }
  145.         return *ptr_;
  146.     }
  147.  
  148.     void Reset() {
  149.         is_initialized_ = false;
  150.         ptr_ = nullptr;
  151.     }
  152.  
  153. private:
  154.     // alignas нужен для правильного выравнивания блока памяти
  155.     alignas(T) char data_[sizeof(T)];
  156.     T* ptr_ = nullptr;
  157.     bool is_initialized_ = false;
  158. };
  159.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement