我已经使用硬件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
也一样。
现在,我已经失去了关于动态内存管理的北方,这就是我要问的原因:
感谢您的关注!
答案 0 :(得分:1)
我的经验是,C ++中的类型安全性不仅意味着编译器抱怨类型不匹配。这意味着您通常不必关心数据的内存布局。实际上,C ++标准对某些数据类型的内存布局只有很少的要求。
您的序列化基于直接内存访问,因此,我担心不会有简单的“纯”C ++解决方案,特别是没有通用的编译器/平台独立解决方案。