【原創】自己手寫實現Boost序列化簡易版

来源:https://www.cnblogs.com/churen/archive/2018/11/24/10013742.html
-Advertisement-
Play Games

設計思路 在與多個系統進行網路交互時,序列化是不可缺少的技術。編寫一個C++語言的序列化實現,是練習運用模板元編程的絕佳案例,理解C++模板是如何"面向編譯期編程"的(業內好像沒有這個說法)。序列化對象處理基礎數據類型和類類型,boost的序列化功能劃分得更細緻,基本支持了C++語言的序列化,但是在 ...


設計思路

 

在與多個系統進行網路交互時,序列化是不可缺少的技術。編寫一個C++語言的序列化實現,是練習運用模板元編程的絕佳案例,理解C++模板是如何"面向編譯期編程"的(業內好像沒有這個說法)。序列化對象處理基礎數據類型和類類型,boost的序列化功能劃分得更細緻,基本支持了C++語言的序列化,但是在業務開發中,支持這兩種已經足夠用了。對於基礎數據類型的序列化,需要合理組織序列化的協議格式;對於類類型的序列化,類是由基礎數據類型組成的,最終轉換為基礎數據類型的序列化。

代碼思路

 

序列化實現類class CTextSerialize,反序列化實現類class CTextDeserialize;這兩個類都通過業務類的模板函數serialize以傳參的方式分別實現序列化和反序列化。class CTextSerialize中的重載函數serialize分別實現基礎數據類型和類類型的序列化;class CTextDeserialize中的重載函數deserialize分別實現基礎數據類型和類類型的反序列化。這兩個類在處理類類型序列化/反序列化時,都調用了class CAccess的靜態函數serialize。對於容器vector和map這種特殊的類類型,需要單獨實現偏特化的class CAccess。整體代碼設計思路需要結合完整代碼實現細節進行理解。

完整代碼

 

代碼基於C++98進行編寫,採用gcc4.8.5編譯器編譯,測試運行在CentOS7.3環境。

在main函數中,代碼分為四段:

第一段,採用輸入輸出流操作不同基礎數據類型的變數;

第二段,使用模板判斷變數類型是基礎數據類型還是類類型;

第三段,對基礎數據類型進行序列化和反序列化;

第四段,對類類型進行序列化和反序列化。

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

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

#include <iostream>

#include <sstream>

#include <map>

#include <vector>

#include <stdint.h>

using namespace std;

 

template<typename T>

struct is_class_imp{ //採用boosttype_traits的方式判斷,判斷一個類型是否是一個類類型

typedef char class_type; //一個位元組

typedef int32_t non_class_type; //四個位元組

template<typename C> static class_type is_class_check(void(C::*)(void)); //類類型匹配到的模板函數

template<typename C> static non_class_type is_class_check(...); //基礎類型匹配到的模板函數

 

static const bool value = (sizeof(is_class_check<T>(0)) == sizeof(class_type)); //value的值在編譯期決定

};

template<>

struct is_class_imp<string>{ //模板特化,string可以作為基礎類型處理,其實是類類型

static const bool value = false;

};

template<typename T>

struct is_class : is_class_imp<T>{}; //繼承

 

template<bool C_>

struct bool_plt{}; //用於編譯期條件判斷的模板,bool_plt<true>bool_plt<false>

 

template<typename C_, typename F1, typename F2> //C_編譯期的條件,依據條件判斷,動態定義類型F1F2

struct eval_if{};

template<typename F1, typename F2> //模板偏特化,typename C_

struct eval_if<bool_plt<true>, F1, F2>{ //C_編譯期條件為bool_plt<true>時,定義類型F1

typedef F1 type;

};

template<typename F1, typename F2> //模板偏特化,typename C_

struct eval_if<bool_plt<false>, F1, F2>{ //C_編譯期條件為bool_plt<false>時,定義類型F2

typedef F2 type;

};

 

template<typename Archive, typename T>

class CAccess //對類類型對象,應該序列化還是反序列化的控制函數

{

public:

static void serialize(Archive& ar, T& t){ //調用類類型對象的serialize函數,序列化還是反序列化由ar參數決定

t.serialize(ar);

}

};

template<typename Archive, typename T>

struct CFreeMarshall{ //序列化結構體類型

static void invoke(Archive& ar, const T& t){

CAccess<Archive, T>::marshall(ar, t);

}

};

template<typename Archive, typename T>

struct CFreeDemarshall{ //反序列化結構體類型

static void invoke(Archive& ar, T& t){

CAccess<Archive, T>::demarshall(ar, t);

}

};

template<typename Archive, typename T>

struct CFreeInvoke{ //序列化和反序列化統一調用模版函數,在編譯期決定調用其一

static void invoke(Archive& ar, T& t){

typedef typename eval_if<typename Archive::is_marshall, //假如ar對象是序列化對象

CFreeMarshall<Archive, T>, //定義序列化類型

CFreeDemarshall<Archive, T> >::type typex; //否則定義反序列化類型

typex::invoke(ar, t); //調用序列化或反序列化函數,在編譯期動態判斷決定

}

};

 

template<typename Archive, typename T>

class CAccess<Archive, vector<T> > //模板偏特化,實現vector容器的序列化和反序列化

{

public:

static void serialize(Archive& ar, vector<T>& t) //調用序列化或反序列化函數,在編譯期動態判斷決定

{

CFreeInvoke<Archive, vector<T> >::invoke(ar, t);

}

static void marshall(Archive& ar, const vector<T>& t) //序列化

{

int len = t.size();

ar << len << " ";

for (int i = 0; i < len; i++)

{

ar << t[i] << " ";

}

}

static void demarshall(Archive& ar, vector<T>& t) //反序列化

{

int len = 0;

ar >> len;

t.clear();

for (int i = 0; i < len; i++)

{

T tmp;

ar >> tmp;

t.

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載請註明出處: https://www.cnblogs.com/funnyzpc/p/9501376.html ``` 我先閑扯下,前天(也就是2018年11月16號)的某個時候,忽然有人在QQ上私聊我,一看是公司群以為是有人來慰問新人了,也沒弄清楚身份就調侃起來,就這樣: 問題是:我竟傻乎乎滴沒 ...
  • 1.引入依賴 2.配置信息: 3.es配置啟動類: 4.操作工具類: ...
  • 記一次線程池任務執行異常 一個名為 fetch 線程池負責從Redis中讀取文本數據,將讀取到的文本數據提交給另一個線程池 tw ,將 tw 線程池將任務通過HTTP請求的形式上報給過濾服務。如下圖所示: 一開始採用預設線程池配置方式: 然後只提交三個任務 ,startService() 是個 以 ...
  • 可預測的偽隨機數發生器 漏洞特征:PREDICTABLE_RANDOM在某些關鍵的安全環境中使用可預測的隨機數可能會導致漏洞,比如,當這個值被作為: csrf token;如果攻擊者可以預測csrf的token值的話,就可以發動csrf攻擊 重置密碼的token(通過郵件發送);如果重置密碼的tok ...
  • 1、什麼是Redis?簡述它的優缺點? Redis的全稱是:Remote Dictionary.Server,本質上是一個Key-Value類型的記憶體資料庫,很像memcached,整個資料庫統統載入在記憶體當中進行操作,定期通過非同步操作把資料庫數據flush到硬碟上進行保存。 因為是純記憶體操作,Re ...
  • FileWriter寫數據路徑問題及關閉和刷新方法的區別 ...
  • 一、項目介紹 生鮮超市平臺,通過Vue + Django Rest Framework 搭建整個網站,通過該項目的學習,可以掌握以下技術點: 掌握前端Vue + 後端Django Rest Framework 前後端分離技術 徹底玩轉Restful API的開發流程 掌握Sentry,完成線上系統錯 ...
  • FileWriter剖析 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...