Today I implemented a C++11 template class which allows for Nullable types. The reason for this is that std::optional is not yet available, (I use C++11/14) and I wanted to practice a bit, so I decided to make one myself. Also for portability reasons. (The code has to compile on multiple platforms, namely Linux and Windows. GCC/MSVC)
Can you guys take a look at it and point me to some improvements/changes that might be needed?
Here is the code:
Class Definition:
#include <algorithm>
template<typename T>
class Nullable final
{
private:
union Data
{
Data(){};
~Data(){};
Data(const Data&) = delete;
Data(Data&&) = delete;
Data& operator=(const Data&) = delete;
Data& operator=(Data&&) = delete;
T m_Data;
} m_Data;
bool m_IsUsed = false;
public:
Nullable() = default;
~Nullable();
Nullable(T object);
Nullable(const Nullable& object);
Nullable(Nullable&& object);
Nullable& operator=(const Nullable& object);
Nullable& operator=(Nullable&& object);
Nullable& operator=(const T& object);
Nullable& operator=(T&& object);
bool isInitialized();
void initialize(T&& object);
void initialize(const T& object);
void reset();
void reset(const T& object);
void reset(T&& object);
};
Class Implementation: (In same header file)
template<typename T>
void Nullable<T>::initialize(T&& object)
{
m_IsUsed = true;
m_Data.m_Data = std::move(object);
}
template<typename T>
void Nullable<T>::initialize(const T& object)
{
m_IsUsed = true;
m_Data.m_Data = object;
}
template<typename T>
Nullable<T>::~Nullable()
{
if(m_IsUsed)
m_Data.m_Data.~T();
}
template<typename T>
Nullable<T>& Nullable<T>::operator=(const Nullable<T>& rhs)
{
if(&rhs == this)
return *this;
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = rhs.m_Data.m_Data;
m_IsUsed = true;
return *this;
}
template<typename T>
Nullable<T>& Nullable<T>::operator=(Nullable<T> && rhs)
{
if(&rhs == this)
return *this;
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = std::move(rhs.m_Data.m_Data);
m_IsUsed = true;
rhs.m_IsUsed = false;
return *this;
}
template<typename T>
Nullable<T>::Nullable(const Nullable<T> & rhs)
{
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = rhs.m_Data.m_Data;
m_IsUsed = true;
}
template<typename T>
Nullable<T>::Nullable(Nullable<T> && rhs)
{
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = std::move(rhs.m_Data.m_Data);
rhs.m_IsUsed = false;
m_IsUsed = true;
}
template<typename T>
bool Nullable<T>::isInitialized()
{
return m_IsUsed;
}
template<typename T>
void Nullable<T>::reset()
{
m_Data.m_Data.~T();
}
template<typename T>
void Nullable<T>::reset(const T& object)
{
if(&object == this)
return;
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = object;
m_IsUsed = true;
}
template<typename T>
void Nullable<T>::reset(T&& object)
{
if(&object == this)
return;
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = std::move(object);
m_IsUsed = true;
}
template<typename T>
Nullable<T>& Nullable<T>::operator=(const T& object)
{
if(&object == &this->m_Data.m_Data)
return *this;
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = object;
m_IsUsed = true;
return *this;
}
template<typename T>
Nullable<T>& Nullable<T>::operator=(T&& object)
{
if(&object == &this->m_Data.m_Data)
return *this;
if(isInitialized())
{
m_Data.m_Data.~T();
}
m_Data.m_Data = std::move(object);
m_IsUsed = true;
return *this;
}
template<typename T>
Nullable<T>::Nullable(T object)
{
m_Data.m_Data = object;
m_IsUsed = true;
}
std::aligned_storageinstead of the union. \$\endgroup\$union Data? Can you point at some reference that shows what you are trying to achieve with this? \$\endgroup\$