1、allocator.h文件
該文件定義了一個分配器模版,該文件主要使用了內存對齊控制、rebind機制(C++ 標準庫的分配器接口要求提供 rebind 機制,以支持不同類型的分配)、::operator new、std::addressof等技術。
- 內存對齊控制:之所以先保存當前內存對齊方式,最后再恢復,是想把json對象的內存對齊方式和使用它的對象的內存方式隔離開
#pragma pack(push) //保存當前內存對齊方式
#pragma pack() // 使用編譯器默認內存對齊方式... // 使用默認內存對齊方式的代碼
#pragma pack(pop) // 恢復之前的內存對齊方式
- rebind機制: C++ 標準庫的分配器接口要求提供 rebind 機制,以支持不同類型的分配,rebind 機制可以理解為允許分配器為不同類型的對象分配內存空間。這種機制使得標準庫容器能夠使用相同的分配器實例來分配其所有元素類型的內存。rebind 機制允許你通過一個分配器類型生成另一個類型的分配器。例如,如果你有一個 SecureAllocator,你可以通過 rebind 機制得到一個SecureAllocator,從而使用相同的分配器為 double 類型的對象分配內存。使用方式如下:
SecureAllocator<int> intAlloc;
SecureAllocator<int>::rebind<double>::other doubleAlloc;
- ::operator new: 只分配空間而不調用構造函數,如果直接new,既分配空間又調用構造函數。前者需要程序員控制調用構造函數,析構函數,銷毀空間,后者直接delete或delete []即可。
- std::addressof是C++11新引入的,它的主要作用是獲取對象的地址,這樣的優點是放在類對&進行重寫而改變了取地址的含義。
#ifndef JSON_ALLOCATOR_H_INCLUDED
#define JSON_ALLOCATOR_H_INCLUDED#include <cstring>
#include <memory>
/*
預處理命令#pragma pack(push)用來保存當前的內存對齊方式
#pragma pack()用來使用編譯器默認的內存對齊方式
*/
#pragma pack(push)
#pragma pack()namespace Json {
template <typename T> class SecureAllocator {
public:// 類型定義using value_type = T;using pointer = T*;using const_pointer = const T*;using reference = T&;using const_reference = const T&;using size_type = std::size_t;using difference_type = std::ptrdiff_t;// 默認構造函數SecureAllocator() {}// 拷貝構造函數模板template <typename U> SecureAllocator(const SecureAllocator<U>&) {}// rebind 結構體模板template <typename U> struct rebind { using other = SecureAllocator<U>; };// 分配內存pointer allocate(size_type n) {return static_cast<pointer>(::operator new(n * sizeof(T)));}// 釋放內存void deallocate(pointer p, size_type n) {memset_s(p, n * sizeof(T), 0, n * sizeof(T));::operator delete(p);}// 在已分配內存上構造對象,就地構造template <typename... Args> void construct(pointer p, Args&&... args) {::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);}// 獲取對象的地址pointer address(reference x) const { return std::addressof(x); }const_pointer address(const_reference x) const { return std::addressof(x); }// 獲取最大可分配數量size_type max_size() const { return size_t(-1) / sizeof(T); }// 在已分配內存上銷毀對象void destroy(pointer p) {p->~T();}
};// 比較操作符
template <typename T, typename U>
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {return true;
}template <typename T, typename U>
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {return false;
}
} // namespace Json//恢復原有的內存對齊方式
#pragma pack(pop)#endif // JSON_ALLOCATOR_H_INCLUDED
2、config.h文件
- 動態庫導入導出符號在不同的平臺和編譯器中的處理方式不一樣,需要對導出的符號進行特定的處理,以確保正確導出和導入。JSON_DLL_BUILD:在編譯動態庫時定義。用于標識正在編譯動態庫。JSON_DLL:在使用動態庫時定義。用于標識正在使用動態庫。JSON_API:根據不同的編譯器和平臺,定義導出和導入符號的宏。可以理解為在編譯動態庫和使用動態庫時,JSON_API的值是不一樣的。
// Export macros for DLL visibility
#if defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#elif defined(__GNUC__) || defined(__clang__)
#define JSON_API __attribute__((visibility("default")))
#endif // if defined(_MSC_VER)#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#endif // ifdef JSON_DLL_BUILD#if !defined(JSON_API)
#define JSON_API
#endif
- MSVC版本兼容性
#if defined(_MSC_VER) && _MSC_VER < 1800
#error \"ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
#endif#if defined(_MSC_VER) && _MSC_VER < 1900
// As recommended at
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,const char* format, ...);
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
#else
#define jsoncpp_snprintf std::snprintf
#endif
- 根據編譯器版本設置棄用宏JSONCPP_DEPRECATED,它可以向編譯器表明某個函數或變量已被棄用,并提供一個棄用消息。
#ifdef __clang__
#if __has_extension(attribute_deprecated_with_message)
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
#endif // GNUC version
#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates// MSVC)
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
#endif // __clang__ || __GNUC__ || _MSC_VER#if !defined(JSONCPP_DEPRECATED)
#define JSONCPP_DEPRECATED(message)
#endif // if !defined(JSONCPP_DEPRECATED)#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif
- 類型定義,std::conditional:根據條件選擇不同的類型,std::basic_string:使用自定義分配器的字符串類型,std::basic_istringstream 和 std::basic_ostringstream:使用自定義分配器的字符串輸入輸出流
namespace Json {
using Int = int;
using UInt = unsigned int;
#if defined(JSON_NO_INT64)
using LargestInt = int;
using LargestUInt = unsigned int;
#undef JSON_HAS_INT64
#else
#if defined(_MSC_VER)
using Int64 = __int64;
using UInt64 = unsigned __int64;
#else
using Int64 = int64_t;
using UInt64 = uint64_t;
#endif
using LargestInt = Int64;
using LargestUInt = UInt64;
#define JSON_HAS_INT64
#endiftemplate <typename T>
// JSONCPP_USING_SECURE_MEMORY 為true,使用SecureAllocator<T>, 為false,使用std::allocator<T>
using Allocator = typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>, std::allocator<T>>::type;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using IStringStream = std::basic_istringstream<String::value_type, String::traits_type, String::allocator_type>;
using OStringStream = std::basic_ostringstream<String::value_type, String::traits_type, String::allocator_type>;
using IStream = std::istream;
using OStream = std::ostream;
}