最近我一直在尝试更新一些代码以利用标准的C 库功能,而不是旧的C样式函数。特别是,我尝试做以下(为简单起见的人为工作示例 - 我知道代码很丑陋,但它简单地说明了问题):
std::vector<int> vData;
vData.push_back(10990);
vData.push_back(11990);
vData.push_back(12990);
vData.push_back(13990);
unsigned char szBuffer[100];
memset(szBuffer,0,sizeof(szBuffer));
std::copy(vData.begin(),vData.end(),szBuffer);
我期望这将以与我要替换的代码相似的方式行为:
memcpy(szBuffer,&vData[0],sizeof(int)*vData.size());
但要调试代码,很明显,我编写的std::copy
代码仅写入unsigned char
缓冲区的前4个字节,而不是向量中4个整数的完整位模式。有人可以告诉我我做错了什么,还是简单地说我不能以这种方式使用std::copy
并且应该坚持使用memcpy
?
坚持使用memcpy
,std::copy
是智能的,它了解涉及的类型,并使用标准转换正确地将int
转换为unsigned char
。memcpy
是无知的,这就是您想要的。
我期望这将以与我要替换的代码相似的方式行为...
书面的std::copy
不能以与std::memcpy
或std::memmove
相似的方式行为,因为std::vector<int>
的元素与unsigned char szBuffer[100]
的元素之间的类型不匹配。克服这种类型不匹配的一种方法是将szBuffer
投射到int*
:
std::copy(vData.begin(),vData.end(),reinterpret_cast<int*>(szBuffer));
reinterpret_cast
是个人喜好问题。我宁愿看到一些尖叫的东西"危险,危险,鲁滨逊!"对于可以在隐藏但不会消除UB潜力的C风格的铸件上调用不确定行为的事物。我(和我的项目经理霸主)可以为reinterpret_cast
。
UB的潜力是真实的,因为不能保证由于对齐问题而有效。
还请注意,不能保证std::copy
将永远通过memcpy
或memmove
实现。标准中没有一个单词(2003年或2011年)说std::copy
需要通过memcpy
或memmove
实现。(顺便说一句:在我看到的每个实施中,std::copy
都将通过std::memmove
实施,如果这样做的话,就好像"使用了"幼稚的实现"一样。)
从std::memcpy
切换到std::copy
的唯一原因是美学。有时美学会阻碍。"愚蠢的一致性是小小的妖精。"我建议坚持使用std::memcpy
。它完全可以做您想要的,并且此用法是安全的,因为没有重叠,并且由于缓冲区的尺寸适当。
,因为标准是行为(如果不是确切的实现) std::copy
等于:
namespace std {
template< typename InIter, typename OutIter >
OutIter std::copy( InIter begin, InIter end, OutIter outp )
{
for( ; begin != end; ++begin, ++outp )
{
*outp = *begin;
}
return outp;
}
}
这意味着它会逐元复制成员,递增每个迭代器并返回输出中的下一个写入位置。
这与Memcpy不同,这是您在这里真正想要的。使用memcpy没有错(即使某个Microsoft编译器告诉您它是不安全的,它可能是,但是如果您不正确驾驶卡车,那就驾驶卡车,这并不意味着没有人可以开车一个)。
将向量的内容解释为原始内存,将 reinterpret_cast
使用至 unsigned char *
:
std::copy(reinterpret_cast<unsigned char *>(&*vData.begin()),
reinterpret_cast<unsigned char *>(&*vData.end()), szBuffer);
您需要间接并取下开始和结束元素的地址,因为不能保证vector::iterator
是一种指针类型。
这是reinterpret_cast
的少数保证安全用途之一。