optional< T>
c++14中将包含一个std::optional类,optional< T>内部存储空间可能存储了T类型的值也可能没有存储T类型的值。当optional< T>被初始化之后,可以通过operator bool() 获得true的返回值,否则返回值为false,这样可以知道该optional内部是否有合法的一个T对象,进而继续访问。
optional<int> op; //未初始化,operator bool()为false
if (op)
cout << *op << endl;
optional<int> op1 = 1;
if (op) //经过初始化,返回true
cout << *op1 << endl;
c++11实现optional
optional< T>要容纳T类型的对象,因此需要一个缓冲区来保存,该缓冲区可以使用普通的char数组,但是char xx[]是一字节对齐,xx很有可能不在MyClass对齐的位置上。这样调用placement new构造内存块,可能会引起效率问题或出错,因此需要用内存对齐的缓冲区 std::aligned_storage.
template<std::size_t Len, std::size_t Align>
struct aligned_storage;
Len表示所存储类型的size,通过sizeof(T)获得;Align表示该类型内存对齐的大小,通过std::alignment_of<T>::value获得。
std::aligned_storage一般和placement new结合起来使用:
struct A{
int avg;
A(int a, int b):avg((a+b)/2){};
};
typedef std::aligned_storage<sizeof(A), std::aligenment_of<A>::value>::type Aligned_A;
int main(){
Aligned_A a, b; //获得了两块内存区,大小和对齐方式指定
new (&a)A(10,20); //placement new,在内存块a处 构造了一个A对象
b = a;
return 0;
}
Optional的实现【代码均参考网上】
#include<type_traits>
#include<iostream>
#include<string>
#include<map>
using namespace std;
template<typename T>
class Optional
{
using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
public:
Optional() : m_hasInit(false) {}
Optional(const T& v)
{
Create(v);
}
Optional(T&& v) : m_hasInit(false)
{
Create(std::move(v));
}
~Optional()
{
Destroy();
}
Optional(const Optional& other) : m_hasInit(false)
{
if (other.IsInit())
Assign(other);
}
Optional(Optional&& other) : m_hasInit(false)
{
if (other.IsInit())
{
Assign(std::move(other));
other.Destroy();
}
}
Optional& operator=(Optional &&other)
{
Assign(std::move(other));
return *this;
}
Optional& operator=(const Optional &other)
{
Assign(other);
return *this;
}
template<class... Args>
void emplace(Args&&... args)
{
Destroy();
Create(std::forward<Args>(args)...);
}
bool IsInit() const { return m_hasInit; }
explicit operator bool() const {
return IsInit();
}
T& operator*()
{
if (IsInit())
{
return *((T*)(&m_data));
}
throw std::logic_error("is not init");
}
T const& operator*() const
{
if (IsInit())
{
return *((T*)(&m_data));
}
throw std::logic_error("is not init");
}
bool operator == (const Optional<T>& rhs) const
{
return (!bool(*this)) != (!rhs) ? false : (!bool(*this) ? true : (*(*this)) == (*rhs));
}
bool operator < (const Optional<T>& rhs) const
{
return !rhs ? false : (!bool(*this) ? true : (*(*this) < (*rhs)));
}
bool operator != (const Optional<T>& rhs)
{
return !(*this == (rhs));
}
private:
template<class... Args>
void Create(Args&&... args)
{
new (&m_data) T(std::forward<Args>
(args)...);
m_hasInit = true;
}
void Destroy()
{
if (m_hasInit)
{
m_hasInit = false;
((T*)(&m_data))->~T();
}
}
void Assign(const Optional& other)
{
if (other.IsInit())
{
Copy(other.m_data);
m_hasInit = true;
}
else
{
Destroy();
}
}
void Assign(Optional&& other)
{
if (other.IsInit())
{
Move(std::move(other.m_data));
m_hasInit = true;
other.Destroy();
}
else
{
Destroy();
}
}
void Move(data_t&& val)
{
Destroy();
new (&m_data) T(std::move(*((T*)
(&val))));
}
void Copy(const data_t& val)
{
Destroy();
new (&m_data) T(*((T*)(&val)));
}
private:
bool m_hasInit;
data_t m_data;
};
class MyClass{
public:
MyClass(int a, int b) :
x_(a), y_(b){};
void print(){
cout << "x_ = " << x_ << endl;
cout << "y_ = " << y_ << endl;
}
private:
int x_;
int y_;
};
void TestOptional()
{
Optional<string> a("ok");
Optional<string> b("ok");
Optional<string> c("aa");
c = a;
if (c<a)
cout << '<' << endl;
if (a == b)
cout << '=' << endl;
map<Optional<string>, int> mymap;
mymap.insert(std::make_pair(a, 1));
mymap.insert(std::make_pair(c, 2));
auto it = mymap.find(a);
cout << it->second << endl;
Optional<MyClass> d;
d.emplace(10, 20);
(*d).print();
}
int main(){
TestOptional();
return 0;
}