Created
October 15, 2019 15:20
-
-
Save minya/7f146ddb1a6f61e87e32df1bc097c336 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <memory> | |
// Исключение этого типа должно генерироваться при обращении к "пустому" Optional в функции Value | |
struct BadOptionalAccess { | |
}; | |
template <typename T> | |
class Optional { | |
private: | |
// alignas нужен для правильного выравнивания блока памяти | |
alignas(T) unsigned char data[sizeof(T)]; | |
bool defined = false; | |
public: | |
Optional() = default; | |
Optional(const T& elem) { | |
new (data) T(elem); | |
defined = true; | |
} | |
Optional(T&& elem): | |
defined(true) { | |
new (data) T(std::move(elem)); | |
} | |
Optional(const Optional& other) { | |
if (other.HasValue()) { | |
new (data) T(other.Value()); | |
defined = true; | |
} | |
} | |
Optional(Optional&& other) : defined(other.defined) { | |
if (other.defined) { | |
new (data) T(std::move(other.Value())); | |
} | |
} | |
Optional& operator=(const T& elem) { | |
if (!defined) { | |
new (data) T(elem); | |
defined = true; | |
} else { | |
*reinterpret_cast<T*>(data) = elem; | |
} | |
return *this; | |
} | |
Optional& operator=(T&& elem) { | |
if (HasValue()) { | |
Reset(); | |
} | |
*reinterpret_cast<T*>(data) = std::move(elem); | |
defined = true; | |
return *this; | |
} | |
Optional& operator=(const Optional& other) { | |
if (!defined) { | |
if (other.defined) { | |
new (data) T(other.Value()); | |
defined = true; | |
} | |
} else { | |
if (!other.defined) { | |
Reset(); | |
} else { | |
*reinterpret_cast<T*>(data) = other.Value(); | |
} | |
} | |
return *this; | |
} | |
Optional& operator=(Optional&& other) { | |
if (defined) { | |
Reset(); | |
} | |
if (other.defined) { | |
*reinterpret_cast<T*>(data) = std::move(*other); | |
defined = true; | |
other.defined = false; | |
} | |
return *this; | |
} | |
bool HasValue() const { | |
return defined; | |
} | |
// Эти операторы не должны делать никаких проверок на пустоту. | |
// Проверки остаются на совести программиста. | |
T& operator*() { | |
return *reinterpret_cast<T*>(data); | |
} | |
const T& operator*() const { | |
return *reinterpret_cast<const T*>(data); | |
} | |
T* operator->() { | |
return reinterpret_cast<T*>(data); | |
} | |
const T* operator->() const { | |
return reinterpret_cast<const T*>(data); | |
} | |
// Генерирует исключение BadOptionalAccess, если объекта нет | |
T& Value() { | |
if (!defined) { | |
throw BadOptionalAccess{}; | |
} | |
return *reinterpret_cast<T*>(data); | |
} | |
const T& Value() const { | |
if (!defined) { | |
throw BadOptionalAccess{}; | |
} | |
return *reinterpret_cast<const T*>(data); | |
} | |
void Reset() { | |
if (!defined) | |
return; | |
defined = false; | |
T* data_ptr = reinterpret_cast<T*>(data); | |
if (data_ptr != nullptr) { | |
data_ptr->~T(); | |
} | |
//delete [] data; | |
} | |
~Optional() { | |
Reset(); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment