最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

C++ 11 实现类似boost库和Scala的optional变量

XAMPP案例 admin 516浏览 0评论

实现原理,
代码示例是照着《深入应用C++11》抄的。

  1. 使用变长模板参数构造任意对象。
  2. 使用std::aligned_storage实现任意长度对象的内存对齐。
  3. 使用std::forward减少参数拷贝,实现右值引用的完美转发。
    optional.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#ifndef _OPTIONAL_HPP_
#define _OPTIONAL_HPP_

#include <type_traits>
#include <functional>

template <typename T>
class Optional {
using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;

public:
Optional() {}
Optional(const T& v) {
Create(v);
}

Optional(T&& v) {
Create(std::move(v));
}

~Optional() {
Destroy();
}

Optional(const Optional& other) {
if(other.IsInit()) {
Assign(other);
}
}

Optional(Optional&& other) {
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)…);
}

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 {
// 1. 两个对象的初始化状态不等, return false
// 2. 如果初始化状态相等,当前对象没有被初始化,说明两个对象都没有被初始化,那相等,return true
// 3. 状态相等,且都被初始化了,比较Optional对象指向的值
return (!bool(*this)) != (!rhs) ? false: (!bool(*this)) ? true: (*(*this)) == (*rhs);
}

bool operator < (const Optional<T>& rhs) const {
// 1. 如果右值没有初始化, 不可能小于空值,return false
// 2. 如果右值不为空,左值为空,肯定小于 return true
// 3. 左值,右值都不为空,比较值
return !rhs ? false: (!(bool(*this))) ? true: ((*(*this)) < (*rhs));
}

bool operator != (const Optional<T>& rhs) const {
return !(*this == (rhs));
}

bool IsInit() const {
return m_hasInit;
}

private:
template <typename… 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的析构函数释放资源
((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 = false;
data_t m_data;
};
#endif

main.cpp测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include “optional.hpp”
#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

#include <cstdlib>

struct MyStruct {
MyStruct() {}

MyStruct(int a, int b): m_a(a), m_b(b) {}
int m_a;
int m_b;
};

void testOp() {
Optional<string> a(“ok”);
Optional<string> b(“cancel”);
Optional<string> c(“aa”);

Optional<string> d = a;
cout << “d=” << *d << endl;

Optional<MyStruct> op;
op.emplace(1, 2);

MyStruct t;
if(op) {
t = *op;
}

cout << “t.m_a= ” << t.m_a << ” t.m_b= ” << t.m_b << endl;
op.emplace(3, 4);

if(op) {
t = *op;
}

cout << “t.m_a= ” << t.m_a << ” t.m_b= ” << t.m_b << endl;
}

int main(void) {

testOp();

cout << “请按任意键继续…” << endl;
getchar();
return 0;
}

Makefile文件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
TAR=main
WORKSPACE_DIR=.
CC:=g++

.PHONY: build clear all

build:
$(CC) -std=c++11 $(WORKSPACE_DIR)/optional.hpp $(WORKSPACE_DIR)/main.cpp -g -o $(TAR)

all: clear build

clear:
rm -rf $(TAR)

测试程序的输出如下,

f0004

转载请注明:XAMPP中文组官网 » C++ 11 实现类似boost库和Scala的optional变量

您必须 登录 才能发表评论!