optional的应用场景
函数返回无效对象
有时根据某个条件去查找对象时,如果查找不到对象时就会返回一个无效值,这不表明函数执行失败,而是表明函数正确执行了,但是结果却不是有用的值,这时就可以返回一个未初始化的optional对象出去,在外面判断这个optional对象是否有效对象是否被初始化,如果没有被初始化就表明这个值是无效的。
boost中的optional就实现了这种未初始化的概念,boost.optional的基本用法很简单:
复制代码
optional op;
if(op)
cout<<*op<
optional op1 = 1;
if(op1)
cout<<*op1<
复制代码
第一个op由于没有被初始化,所以它是一个无效值,将不会输出打印信息,第二个op被初始化为1,所以它是一个有效值,将会输出1。optional经常用于函数返回值,像boost.property_tree中就有很多optional接口(关于boost.property_tree可以参考我前面博文的介绍:),比如get_child_optional接口,返回一个optional对象,外面需要判断它是否是一个有效值来确定是否取到了对应的子节点。
c++11实现optional
c++11中目前还没有optional,在c++14中将会增加std::optional功能和用法和boost.optional类似。在c++14中的std::optional出来之前,如果不想依赖boost库的话,就用c++11实现一个optional,也不是难事。
c++11实现optional需要注意的问题
1.内部存储空间
由于optional需要容纳T的值,所以需要一个缓冲区保存这个T,这个缓冲区不能用普通的char数组,需要用内存对齐的缓冲区,这里还是采用std::aligned_storage,关于这个可以参考我前面的博文中对std::aligned_storage的讨论。
2.拷贝构造函数和赋值构造函数
需要注意拷贝和赋值时,内部状态和缓冲区销毁的问题。内部状态用来标示该optional是否被初始化,当已经初始化时需要先将缓冲区清理一下。需要增加右值版本优化效率。
来看看具体的实现吧:
复制代码
#include
template
class Optional
{
using data_t = typename std::aligned_storage::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
void emplace(Args&&... args)
{
Destroy();
Create(std::forward(args)...);
}
bool IsInit() const { return m_hasInit; }
explicit operator bool() const { return IsInit();
}
T& operator*()
{
return *((T*) (&m_data));
}
T const& operator*() const
{
if (IsInit())
{
return *((T*) (&m_data));
}
throw std::exception("");
}
bool operator == (const Optional& rhs) const
{
return (!bool(*this)) != (!rhs) false : (!bool(*this) true : (*(*this)) == (*rhs));
}
bool operator < (const Optional& rhs) const
{
return !rhs false : (!bool(*this) true : (*(*this) < (*rhs)));
}
bool operator != (const Optional& rhs)
{
return !(*this == (rhs));
}
private:
template
void Create(Args&&... args)
{
new (&m_data) T(std::forward
(args)...);
m_hasInit = true;
}
void Destroy()
{
if (m_hasInit)
{
m_hasInit = false;
((T*) (&m_data))->~T();
}
}
void As