JsonCPP源码分析——分配器和配置器

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
#endif

template <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;
}
  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值