1. optional类的实现
(1)optional的功能
①optional<T>的内部存储空间可能存储了T类型的值,也可能没有。只有当optional被T初始化之后,这个optional才是有效的。否则是无效的。它实现了未初始化的概念。
②optional可以用于解决函数返回无效值的问题。当函数返回一个未初始化的Optional对象时,表明函数正确执行了,只是结果不是有用的值。
③举例:optional<int> op; //未被初始化。 optional<int> op = 1; //初始化。
(2)实现细节
①由于optional<T>需要容纳T的值,所以需要一个缓冲区来保存它,但考虑到内存对齐,需要将T指定在对齐的位置上。可以通过std::alignment_of <T>::value来获取T的内存对齐大小。并通过std::aligned_storage<sizeof(T), aligned(T)>来定义T的内存对齐类型(该模板的本质就重新定义T经对齐后的一种新类型)。
template<unsigned size, unsigned alignment> struct aligned_storage { using type = struct { alignas(alignment) unsigned char data[size]; }; };
②std::aligned_storage一般和placement_new结合使用(见Optional类的create函数),用于初始化由std::aligned_storage定义的一片内存空间。
③增加一个m_hasInit标记来记录T空间是否己经初始化。
【编程实验】Optional类的实现
//Optional.hpp
#ifndef _OPTIONAL_H_ #define _OPTIONAL_H_ #include <type_traits> #include <utility> //for std::forward #include <stdexcept> template <typename T> class Optional { //std::alignment_of<T>::value获取T的内存对齐大小,std::aligned_storage将T重定义为对齐后的类型 using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type; private: data_t m_data; //内存对齐缓冲区 bool m_hasInit; //是否己经初始化 private: //调用placement_new来创建T对象 template<class... Args> void create(Args... args) //可以接收左右值 { new (&m_data) T(std::forward<Args>(args)...); //调用T的构造函数来初始化m_data空间 m_hasInit = true; } //销毁缓冲区的对象 void destroy() { if(m_hasInit){ m_hasInit = false; ((T*)(&m_data))->~T(); //调用T的析构函数 } } //缓冲区的拷贝 void copy(const data_t& val) { destroy(); new (&m_data) T(*((T*)(&val))); } //缓冲区的移动 void move(data_t&& val) { destroy(); //调用T的移动构造函数进行移动 new (&m_data) T(std::move(*((T*)(&val)))); } //Optional赋值操作(左值版本) void assign(const Optional& other) { if(other.isInit()){ copy(other.m_data); m_hasInit = true; }else{ destroy(); } } //Optional赋值操作(右值版本) void assign(Optional&& other) { if(other.isInit()){ move(std::move(other.m_data)); m_hasInit = true; other.destroy(); //other失去资源控制权 }else{ destroy(); } } public: Optional():m_hasInit(false){}; Optional(const T& v) { create(v); } Optional(T&& v) : m_hasInit(false) { create(std::move(v)); } 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(); } } //根据参数创建对象,如emplace(1,2); template<class ...Args> void emplace(Args&& ...args) { destroy(); create(std::forward<Args>(args)...); } Optional& operator=(const Optional& other) { assign(other); return *this; } Optional& operator=(Optional&& other) { assign(std::move(other)); return *this; } explicit operator bool() const //类型转换函数,如if(op) { return isInit(); } T& operator*() { if(isInit()){ return *((T*)(&m_data)); } throw std::logic_error{"try to get data in a Optional which is not initialized"}; } const T& operator*() const { if(isInit()){ return *((T*)(&m_data)); } throw std::logic_error{"try to get data in a Optional which is not initialized"}; } T* operator->() { return &operator*(); } const T* operator->() const { return &operator*(); } bool operator==(const Optional<T>& rhs) const { bool bInit = bool(*this); return ( !bInit != (!rhs) ? //*this和rhs中一个初始化,一个未初始化 false : !bInit ? true : (*(*this) == (*rhs)) //两者都未初始化,返回true //两者都初始化时,比较两个T对象是否相等 ); } bool operator<(const Optional<T>& rhs) const { bool bInit = bool(*this); return !rhs ? false : (!bInit ? true : (*(*this) < (*rhs))); } bool operator!=(const Optional<T>& rhs) const { return !(*this == rhs); } bool isInit() const {return m_hasInit;} ~Optional() { destroy(); } }; #endif
//main.cpp
#include "Optional.hpp" #include <iostream> using namespace std; struct Test { Test() : m_a(0), m_b(0){} Test(int a, int b) : m_a(a), m_b(b){} int m_a; int m_b; void show() { cout << "a = "<< m_a << ", b = " << m_b << endl; } }; void TestOptional() { const Optional<string> a("ok"); Optional<string> b("ok"); Optional<string> c("aa"); Optional<string> d = b; Optional<string> e; cout << (e<b) << endl; //true cout << (b==d) << endl; //true cout << *c << endl; //cout << *e << endl; //error Optional<Test> op; op.emplace(1, 2); (*op).show(); Test t; if(op) //判断op是否被初始化 t = *op; t.show(); op.emplace(3, 4); t = *op; t.show(); } int main() { TestOptional(); return 0; } /*输出结果: e:\Study\C++11\23>g++ -std=c++11 test.cpp e:\Study\C++11\23>a.exe 1 1 aa a = 1, b = 2 a = 1, b = 2 a = 3, b = 4 */
2. 惰性求值性:Lazy类的实现
(1)Lazy类的功能
①惰性求值一般用于函数式编程语言中。
②可实现函数的延迟调用,函数参数被绑定后并不立即调用,而是在以后的某个时候调用。
③可实现大对象数据的延迟加载。如当初始化某个对象时,该对象引用了一个大对象,但很多时候并不马上获取该对象的数据,就可以延迟加载这个大对象。
(2)实现细节
①借助lambda表达式,将函数封装到lambda表达式中,而不是马上求值,在需要的时候再调用lambda表达式去求值。
②std::function用于保存传入的函数,并延迟到后面需要使用值的时候才执行,函数的返回值放到一个Optional对象中。Optional对象是否被初始化,来判断大对象是否己加载。
③辅助函数lazy的作用是方便使用Lazy类, Lazy<T>中的T用来表示返回值类型大对象的类型,这也是被封装的函数返回值类型,可利用std::result_of来获取该返回值类型。
【编程实验】Lazy类的实现
//Lazy.hpp
#ifndef _LAZY_H_ #define _LAZY_H_ #include "Optional.hpp" #include <functional> #include <type_traits> #include <utility> //for std::forward template<typename T> struct Lazy { private: Optional<T> m_value; std::function<T()> m_func; public: Lazy(){} //保存需要延迟执行的函数及其参数 template<typename Func, typename ...Args> Lazy(Func&& f, Args&&... args) { m_func = [&f, &args...]{return f(args...);}; } //延迟执行,将结果放到Optional中缓存起来,下次不用重新计算就可以直接返回结果 T& value() { if(! m_value.isInit()){ m_value = m_func(); } return *m_value; } bool isValueCreated() const { return m_value.isInit(); } }; //辅助函数,简化Lazy的调用 template<class Func, typename... Args> Lazy<typename std::result_of<Func(Args...)>::type> //返回值类型Lazy<T> lazy(Func&& fun, Args&&... args) { using ret_type_t = typename std::result_of<Func(Args...)>::type; return Lazy<ret_type_t>(std::forward<Func>(fun), std::forward<Args>(args)...); } #endif // _LAZY_H_
//main.cpp
#include "Lazy.hpp" #include <iostream> #include <memory> //for std::shared_ptr using namespace std; struct BigObject { BigObject() { cout << "lazy load big object..." << endl; } }; struct Test { private: Lazy<std::shared_ptr<BigObject>> m_obj; public: Test() { m_obj = lazy([]{return std::make_shared<BigObject>();}); } void load() { m_obj.value(); } }; int Foo(int x) { return x * 2; } void TestLazy() { //带参数的普通函数 int a = 4; auto lazy1 = lazy(Foo, a); cout << lazy1.value() << endl; //8 //不带参数的lambda表达式 Lazy<int> lazy2 = lazy([]{return 12;}); cout << lazy2.value() << endl; //12 //带参的function std::function<int(int)> f = [](int x){return x + 3;}; auto lazy3 = lazy(f, a); cout << lazy3.value() << endl; //7 //延迟加载大对象 Test t; t.load(); //lazy load big object... } int main() { TestLazy(); return 0; }