c++14中将包含一个std::optional类,它的功能和用法和boost的optional类似。optional<T>内部存储空间可能存储了T类型的值也可能没有存储T类型的值,只有当optional被T初始化之后,这个optional才是有效的,否则是无效的,它实现了未初始化的概念。

optional的应用场景

函数返回无效对象
  有时根据某个条件去查找对象时,如果查找不到对象时就会返回一个无效值,这不表明函数执行失败,而是表明函数正确执行了,但是结果却不是有用的值,这时就可以返回一个未初始化的optional对象出去,在外面判断这个optional对象是否有效对象是否被初始化,如果没有被初始化就表明这个值是无效的。

boost中的optional就实现了这种未初始化的概念,boost.optional的基本用法很简单:

optional<int> op;
if(op)
cout<<*op<<endl; optional<int> op1 = ;
if(op1)
cout<<*op1<<endl;

  第一个op由于没有被初始化,所以它是一个无效值,将不会输出打印信息,第二个op被初始化为1,所以它是一个有效值,将会输出1。optional经常用于函数返回值,像boost.property_tree中就有很多optional接口(关于boost.property_tree可以参考我前面博文的介绍:),比如get_child_optional接口,返回一个optional<ptree>对象,外面需要判断它是否是一个有效值来确定是否取到了对应的子节点。

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的值,所以需要一个缓冲区保存这个T,这个缓冲区不能用普通的char数组,需要用内存对齐的缓冲区,这里还是采用std::aligned_storage,关于这个可以参考我前面的博文中对std::aligned_storage的讨论。

2.拷贝构造函数和赋值构造函数

  需要注意拷贝和赋值时,内部状态和缓冲区销毁的问题。内部状态用来标示该optional是否被初始化,当已经初始化时需要先将缓冲区清理一下。需要增加右值版本优化效率。
  来看看具体的实现吧:

#include <type_traits>

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*()
{
return *((T*) (&m_data));
} T const& operator*() const
{
if (IsInit())
{
return *((T*) (&m_data));
} throw std::exception("");
} 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;
};

测试代码:

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, ));
mymap.insert(std::make_pair(c, )); auto it = mymap.find(a);
cout << it->second << endl;
}

可以看到用法和boost.optional的用法保持一致,实现起来也比较简单。

如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。

c++11 boost技术交流群:296561497,欢迎大家来交流技术。

c++11实现c++14的optional的更多相关文章

  1. 剑指offer19:按照从外向里以顺时针的顺序依次打印出每一个数字,4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

    1 题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印 ...

  2. GCC 4.9.0 公布,提升 C++11 和 C++14 特性

    from :http://www.oschina.net/news/51084/gcc-4-9-0 GCC 4.9.0 公布,此版本号是个主要版本号更新,包含了 GCC 4.8.x 系列和之前的 GC ...

  3. Effective Modern C++ 42 Specific Ways to Improve Your Use of C++11 and C++14

    Item 1: Understand template type deduction. Item 2: Understand auto type deduction. Item 3: Understa ...

  4. [C/C++语言标准] ISO C99/ ISO C11/ ISO C++11/ ISO C++14 Downloads

    语言法典,C/C++社区人手一份,技术讨(hu)论(peng)必备 ISO IEC C99 https://files.cnblogs.com/files/racaljk/ISO_C99.pdf IS ...

  5. [C/C++语言标准] ISO C99/ ISO C11/ ISO C++11/ ISO C++14/ISO C++17 Downloads

    语言法典,C/C++社区人手一份,技术讨(hu)论(peng)必备 ISO IEC C99 https://files.cnblogs.com/files/racaljk/ISO_C99.pdf IS ...

  6. 第11月第14天 opengl yuv beginners-tutorials

    1. Here is some snippets of code from my project 'movie player for iOS'. 1. fragment shader varying ...

  7. VMware Workstation 11 中 Ubuntu 14.04 的 VMware Tools 问题 :没有显示共享文件夹

      症状:主要表现在Win7中用VM11安装的Ubuntu14.04中,安装完自带的VMware Tools之后,/mnt/hgfs 中没有前面已经设置好的共享文件夹.   仔细查看了安装过程,发现在 ...

  8. 如何让自己的Dev C++用上C++11,c++14标准

      首先确保Dev C++版本是最新的5.11版 其实用C++11和C++14标准的语法去运行还是会出现结果的,最多warning一下 但完美主义者是不允许这样的 我们可以点击菜单栏的“工具”-> ...

  9. matlab中函数学习——11月14日

    1.记录数组元素个数函数:numel() 解释:number of array 相当于 prod(size(A)) 2.添加路径: addpath('.\3rdparty\ksvd'); 3.pada ...

随机推荐

  1. 第一个go的web程序;调用七牛云存储的音频api问题解决;条件搜寻文件中的内容,字符串拼接+在上一行

    package main import ( "html/template" "io" "io/ioutil" "log" ...

  2. sklearn模型保存

    使用sklearn训练完模型之后,只有将模型持久化到硬盘上,才能方便下次直接使用. 第一种方式:使用pickle >>> from sklearn import svm >&g ...

  3. 【RS】List-wise learning to rank with matrix factorization for collaborative filtering - 结合列表启发排序和矩阵分解的协同过滤

    [论文标题]List-wise learning to rank with matrix factorization for collaborative filtering   (RecSys '10 ...

  4. JavaScript Window History 浏览器的历史

    window.history 对象在编写时可不使用 window 这个前缀. 为了保护用户隐私,对 JavaScript 访问该对象的方法做出了限制. 一些方法: history.back() - 与 ...

  5. 开发 Swift 和 Objective-C 混编的 Framework

    来源:黄文臣 blog.csdn.net/hello_hwc/article/details/58320433 前言 为什么要写这样一篇文章,因为昨天和一个朋友讨论到Swift和Objective C ...

  6. 对simhash算法的一些思考

    http://2588084.blog.51cto.com/2578084/558873

  7. WebService出错 Maximum message size quota for incoming messages (65536) has been exceeded.已超过传入消息(65536)的最大消息大小配额

    WebService应用中如果收到的信息非常大时出错. 1:Maximum message size quota for incoming messages (65536) has been exce ...

  8. 【struts2】Struts2的系统架构

    Struts2的官方文档里附带了Struts2的架构图,下面这张图上展示了Struts2的内部模块,以及它们的运行流程. 这张图上分了好多块,彼此之间相互联系,先浏览一下各块的名字,再留心一下运行图最 ...

  9. 从sys/power/state分析并实现S3C2416的睡眠和唤醒

    环境: PC: debian-7.6.0 ARM CPU: S3C2416 Linux-Kernel: 3.6.0(FriendlyARM) U-boot: 1.3.4 一.问题来源 依据须要,在S3 ...

  10. Swift2.0语言教程之函数嵌套调用形式

    Swift2.0语言教程之函数嵌套调用形式 Swift2.0语言函数嵌套调用形式 在Swift中,在函数中还能够调用函数,从而形成嵌套调用.嵌套调用的形式往往有两种:一种是在一个函数中调用其它函数:还 ...