Pap*_*ter 10 c++ serialization buffer allocator
我已经使用硬件API很长一段时间了,几乎所有我工作过的API都有一个C接口.因此,在很多时候我使用裸new
s,不安全的缓冲和许多用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
和的问题std::copy
:
memcpy
类型不安全,因为它适用于原始void指针,可以管理任何类型的指针,无论它的类型如何,但同时非常灵活,std::copy
缺乏这种灵活性,确保类型安全.乍一看,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;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码运行正常,但看起来很糟糕; 我们正在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);
}
Run Code Online (Sandbox Code Playgroud)
使用上面的方法,内存管理不再是一个问题,std::vector
在范围的最后需要分配,存储和最终解除分配数据的责任,但是std::copy
与指针算术和迭代器算术混合的调用是非常烦人的最后,我忽略std::vector
了sendBuffer
呼叫中的封装.
在之前的尝试之后,我用std::stringstream
s 编写了一些东西,但结果更糟,现在,我想知道是否:
boost::serialization
,但现在我不允许整合它).和:
std::copy
序列化/反序列化目的的最佳用途?(如果有的话).std::copy
复制容器或数组的理由是有限的,将它用于原始内存是一个糟糕的选择吗?alloc
/ free
vs new
/ delete
vsstd::allocator
另一个重要的话题是内存分配.AFAIK的malloc
/ free
功能没有被禁止到C++范围,尽管它们从C是而且new
/ delete
运营商从C++范围和它们不是ANSI C.
new
/ delete
可以在ANSI C中使用吗?假设我需要将所有C风格的代码重构为C++代码,我将摆脱所有alloc
/ free
spreaded arround一些遗留代码,我发现保留动态内存非常混乱,void类型不带任何代码有关大小的信息,因为使用void作为类型保留数据缓冲区是不可能的:
void *Buffer = new void[100]; // <-- How many bytes is each 'void'?
Run Code Online (Sandbox Code Playgroud)
由于缺少纯原始二进制数据指针,因此创建指针是一种常见做法unsigned char
.在char
以等于元件计数和大小.并且unsigned
为了避免数据复制期间意外的签名无符号转换.也许这是一种常见的做法,但它是一团糟...... unsigned char
不是int
也不float
是my_awesome_serialization_struct
我是否被迫选择某种虚拟指针来指向我想要的二进制数据void *
而不是unsigned char *
.
因此,当我需要一个动态缓冲区来进行序列化/反序列化时,我无法避免这些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++ 中的类型安全不仅意味着编译器会抱怨类型不匹配。这意味着您通常不必关心数据的内存布局。事实上,C++标准对某些数据类型的内存布局只有很少的要求。
您的序列化基于直接内存访问,因此,恐怕不会有一个简单的“纯”C++ 解决方案,特别是没有通用的编译器/平台独立解决方案。