用于序列化/反序列化的标准C ++代码

时间:2012-10-15 13:38:33

标签: c++ serialization buffer allocator

我已经使用硬件API很长一段时间了,几乎所有我工作过的API都有一个C接口。因此,在很多时候我使用裸new,不安全的缓冲和许多用C ++代码包装的C函数。最后,C纯代码和C ++纯代码之间的边界在我的脑海中搞砸了(我不知道澄清这个前沿是否有用)。

现在,由于一些新的编码风格要求,我需要将所有怀疑不安全的代码重构为用C ++编写的更安全的代码(假设C ++代码更安全),最终目标是增加代码使用C ++带来的工具实现安全性。

所以,为了摆脱我的困惑,我要求提供有关C / C ++几个主题的帮助。

memcpy vs std::copy

AFAIK memcpy是一个位于C库中的函数,因此它不是C ++ ish;另一方面,std::copy是STL中的一个函数,因此它是纯C ++。

  • 但是,这是真的吗?毕竟,std::copy会调用std::memcpy(进入cstring标题),如果数据可以轻易处理的话。
  • 将所有memcpy次调用重构为std::copy次调用会使代码更加纯粹的C ++"?。

为了处理新的代码样式要求,我决定继续使用memcpy重构,但有关于memcpy和{{1}的一些问题}:

std::copy是类型不安全的,因为它适用于原始void指针,可以管理任何类型的指针,无论它的类型如何,但同时非常灵活,memcpy缺乏这种灵活性确保了类型的安全性。乍一看,std::copy是使用序列化和反序列化例程的最佳选择(这确实是我真正的使用情况),例如,通过自定义串行端口库发送一些值: / p>

memcpy

上面的代码运行正常,但看起来很糟糕;我们正在通过void send(const std::string &value) { const std::string::size_type Size(value.size()); const std::string::size_type TotalSize(sizeof(Size) + value.size()); unsigned char *Buffer = new unsigned char[TotalSize]; unsigned char *Current = Buffer; memcpy(Current, &Size, sizeof(Size)); Current += sizeof(Size); memcpy(Current, value.c_str(), Size); sendBuffer(Buffer, TotalSize); delete []Buffer; } 方法摆脱std::string封装访问它的内部存储器,我们需要处理动态内存的分配和解除分配,使用指针和处理所有值都作为无符号字符(参见下一部分),问题是:还有更好的方法吗?

我尝试使用std::string::c_str()尝试解决上述问题的第一次尝试并不能完全满足我的要求:

std::copy

通过上述方法,内存管理不再是问题,void send(const std::string &value) { const std::string::size_type Size(value.size()); const std::string::size_type TotalSize(sizeof(Size) + value.size()); std::vector<unsigned char> Buffer(TotalSize, 0); std::copy(&Size, &Size + 1, Buffer.begin()); std::copy(value.begin(), value.end(), Buffer.begin() + sizeof(Size)); sendBuffer(Buffer.data(), TotalSize); } 负责分配,存储并最终在范围的末尾解除分配数据,但调用混合{{ 1}}使用指针算术和迭代器算术非常烦人,最后,我忽略了std::vector调用中的std::copy封装。

在之前的尝试之后,我用std::vector编码了一些内容,但结果更糟,现在,我想知道是否:

  • 有一种方法可以安全地序列化对象和值,而不会破坏封装,没有过分或混乱的指针/迭代器算术,没有动态内存管理,或者它只是一个不可能的目标? (是的,我已经听说过sendBuffer,但是现在我不允许整合它。)

  • std::stringstream用于序列化/反序列化的最佳用途是什么? (如果有的话)。
  • 复制容器或数组的boost::serialization基本原理是有限的,将它用作原始内存是一个糟糕的选择吗?

std::copy / std::copy vs alloc / free vs new

另一个重要话题是内存分配。虽然A delete / std::allocator运算符来自C malloc / free运算符来自A new / delete运算符来自于C new / delete函数,但它们不会被禁止进入C ++范围。 C ++范围,它们不是ANSI C。

  • 我对吗?
  • alloc / free可用于ANSI C?

假设我需要将所有C风格的代码重构为C ++代码,我将摆脱所有void *Buffer = new void[100]; // <-- How many bytes is each 'void'? / unsigned char传播的一些遗留代码并且我已经完成了发现保留动态内存非常混乱,void类型不会携带任何有关大小的信息,因为使用void作为类型保留数据缓冲区是不可能的:

char

由于缺少纯原始二进制数据指针,创建指向unsigned的指针是一种常见做法。 unsigned char以便等于元素数量和大小。以及int以避免在数据复制期间发生意外的签名无符号转换。也许这是一种常见做法,但它很混乱... float不是my_awesome_serialization_struct也不是void *也不是unsigned char *如果我&#39 ; m被迫选择某种虚拟指针指向二进制数据我更喜欢unsigned char *而不是alloc

因此,当我需要动态缓冲区进行序列化/反序列化时,我无法避免使用free内容来重构为类型安全缓冲区管理;但当我愤怒地将所有new / delete对重构为std::allocator / std::allocator对时,我读到std::allocator<int>::allocate

new int允许以类型安全的方式保留内存块,乍看之下我敢打赌它会很有用,但在分配std::allocator<int>::deallocate之间没有太大的区别或delete int左右我认为,const char *std::allocator也一样。

现在,我已经失去了关于动态内存管理的北方,这就是我要问的原因:

  • 有一个很好的C ++实践,涉及动态内存管理以实现类型安全管理的序列化/反序列化目的吗?
  • 是否可以避免使用{{1}}进行序列化/反序列化内存缓冲?
  • {{1}}的基本原理以及它在序列化/反序列化范围内的用途是什么? (如果有的话)。

感谢您的关注!

1 个答案:

答案 0 :(得分:1)

我的经验是,C ++中的类型安全性不仅意味着编译器抱怨类型不匹配。这意味着您通常不必关心数据的内存布局。实际上,C ++标准对某些数据类型的内存布局只有很少的要求。

您的序列化基于直接内存访问,因此,我担心不会有简单的“纯”C ++解决方案,特别是没有通用的编译器/平台独立解决方案。