Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <stdexcept>
- #include <utility>
- // Исключение этого типа должно генерироватся при обращении к пустому optional
- class BadOptionalAccess : public std::exception {
- public:
- using exception::exception;
- virtual const char* what() const noexcept override {
- return "Bad optional access";
- }
- };
- template <typename T, typename... S>
- class Optional {
- public:
- Optional() = default;
- Optional(const T& value) : ptr_(new (&data_[0]) T(value)), is_initialized_(true) {}
- Optional(T&& value) : ptr_(new (&data_[0]) T(std::move(value))), is_initialized_(true) {}
- Optional(const Optional& other) {
- if (other.is_initialized_) {
- ptr_ = new (&data_[0]) T(*other.ptr_);
- is_initialized_ = true;
- }
- }
- Optional(const Optional&& other) {
- if (other.is_initialized_) {
- ptr_ = new (&data_[0]) T(std::move(*other.ptr_));
- is_initialized_ = true;
- }
- }
- Optional& operator=(const T& value) {
- if (!is_initialized_) {
- ptr_ = new (&data_[0]) T(value);
- is_initialized_ = true;
- return *this;
- }
- *ptr_ = value;
- return *this;
- }
- Optional& operator=(T&& value) {
- if (!is_initialized_) {
- ptr_ = new (&data_[0]) T(std::move(value));
- is_initialized_ = true;
- return *this;
- }
- *ptr_ = std::move(value);
- return *this;
- }
- Optional& operator=(const Optional& rhs) {
- if (!is_initialized_) {
- if (!rhs.is_initialized_) {
- return *this;
- }
- ptr_ = new (&data_[0]) T(*rhs.ptr_);
- is_initialized_ = true;
- return *this;
- }
- if (!rhs.is_initialized_) {
- ptr_->~T();
- is_initialized_ = false;
- return *this;
- }
- *ptr_ = *rhs.ptr_;
- return *this;
- }
- Optional& operator=(Optional&& rhs) {
- if (!is_initialized_) {
- if (!rhs.is_initialized_) {
- return *this;
- }
- ptr_ = new (&data_[0]) T(std::move(*rhs.ptr_));
- is_initialized_ = true;
- return *this;
- }
- if (!rhs.is_initialized_) {
- ptr_->~T();
- is_initialized_ = false;
- return *this;
- }
- *ptr_ = std::move(*rhs.ptr_);
- return *this;
- }
- void Emplace(S&&... s) {
- if (!is_initialized_) {
- ptr_ = new (&data_[0]) T(std::forward<S>(s)...);
- is_initialized_ = true;
- return;
- }
- ptr_->~T();
- ptr_ = new (&data_[0]) T(std::forward<S>(s)...);
- }
- ~Optional() {
- if (is_initialized_) {
- ptr_->~T();
- }
- }
- bool HasValue() const {
- return is_initialized_;
- }
- // Операторы * и -> не должны делать никаких проверок на пустоту Optional.
- // Эти проверки остаются на совести программиста
- T& operator*() {
- return *ptr_;
- }
- const T& operator*() const {
- return *ptr_;
- }
- T* operator->() {
- return ptr_;
- }
- const T* operator->() const {
- return ptr_;
- }
- // Метод Value() генерирует исключение BadOptionalAccess, если Optional пуст
- T& Value() {
- if (!is_initialized_) {
- throw BadOptionalAccess();
- }
- return *ptr_;
- }
- const T& Value() const {
- if (!is_initialized_) {
- throw BadOptionalAccess();
- }
- return *ptr_;
- }
- void Reset() {
- is_initialized_ = false;
- ptr_ = nullptr;
- }
- private:
- // alignas нужен для правильного выравнивания блока памяти
- alignas(T) char data_[sizeof(T)];
- T* ptr_ = nullptr;
- bool is_initialized_ = false;
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement