[英]Can I use std::copy to copy bit pattern of data from vector of integers to an array of unsigned char
Recently I have been trying to update some code to utilise the standard C++ library functions rather than old C style functions. 最近,我一直在尝试更新一些代码以利用标准的C ++库函数,而不是旧的C样式函数。 In particular, I tried to do the following (artificial working example for simplicity - i know the code is ugly but it illustrates the problem concisely) :
特别是,我尝试执行以下操作(为简化起见,使用人工工作示例-我知道代码很丑陋,但它简洁地说明了问题):
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);
I was expecting that this would behave in a similar way to the code that I am trying to replace : 我期望它的行为与我尝试替换的代码类似:
memcpy(szBuffer,&vData[0],sizeof(int)*vData.size());
but debugging the code, it is clear that the std::copy
code I have written is only writing to the first 4 bytes of the unsigned char
buffer instead of the full bit pattern of the 4 integers in the vector. 但调试代码后,很明显,我编写的
std::copy
代码仅写入unsigned char
缓冲区的前4个字节,而不是向量中4个整数的完整位模式。 Can someone tell me what I have done wrong, or is it simply that I cannot use std::copy
in this way and should stick with memcpy
? 有人可以告诉我我做错了什么吗,还是仅仅因为我不能以这种方式使用
std::copy
而应该坚持使用memcpy
?
Stick to memcpy
, std::copy
is being intelligent, it understands the types involved and is correctly converting int
to unsigned char
using standard conversions. 坚持使用
memcpy
, std::copy
是智能的,它了解所涉及的类型,并使用标准转换将int
正确转换为unsigned char
。 memcpy
is ignorant, that's what you want. memcpy
是无知的,这就是您想要的。
I was expecting that this would behave in a similar way to the code that I am trying to replace ...
我期望它的行为与我尝试替换的代码类似...
That std::copy
as written cannot behave in a similar way to a std::memcpy
or std::memmove
because the type mismatch between the elements of std::vector<int>
versus elements of unsigned char szBuffer[100]
. 编写的
std::copy
不能以类似于std::memcpy
或std::memmove
因为std::vector<int>
元素与unsigned char szBuffer[100]
的元素之间的类型不匹配。 One way to overcome this type mismatch is to cast that szBuffer
to an int*
: 克服此类型不匹配的一种方法是将
szBuffer
转换为int*
:
std::copy(vData.begin(),vData.end(),reinterpret_cast<int*>(szBuffer));
That reinterpret_cast
is a personal preference issue. 该
reinterpret_cast
是个人喜好问题。 I'd much rather see something that screams "Danger, danger, Will Robinson!" 我宁愿看到尖叫的东西“危险,危险,威尔·罗宾逊!” for something that can invoke undefined behavior over a C-style cast that hides but does not remove the potential for UB.
可以通过隐藏但不会消除UB潜力的C样式转换调用未定义行为的东西。 I (and my project manager overlords) can grep for
reinterpret_cast
. 我(和我的项目经理霸主)可以grep来获取
reinterpret_cast
。
The potential for UB here is real as there is no guarantee that this cast is valid due to alignment issues. 此处UB的潜力是真实的,因为不能保证由于对齐问题而导致此强制转换有效。
Note also that there is no guarantee that std::copy
will ever be implemented via memcpy
or memmove
. 还要注意,不能保证
std::copy
可以通过memcpy
或memmove
来实现。 There is not one word in the standard (either 2003 or 2011) that says that std::copy
needs to be implemented via memcpy
or memmove
if possible. 标准(2003年或2011年)中没有一个词表明
std::copy
需要通过memcpy
或memmove
实现。 (Aside: In every implementation I've seen, std::copy
will be implemented via std::memmove
if doing so would work "as if" the naive implementation had been employed.) (旁白:在每一个我所见过的实施,
std::copy
将通过实施std::memmove
,如果这样做“好像”天真的实现已经使用是可行的。)
The only reason to switch from std::memcpy
to std::copy
here is aesthetics. 从
std::memcpy
切换到std::copy
的唯一原因是美观。 Sometimes aesthetics get in the way. 有时美学会妨碍您。 "Foolish consistency is the hobgoblin of small minds."
“愚蠢的一致性是小头脑的妖精。” I recommend sticking with
std::memcpy
. 我建议坚持使用
std::memcpy
。 It does exactly what you want, and this usage is safe because there's no overlap and because the buffer is properly sized. 它完全可以满足您的要求,并且这种用法是安全的,因为没有重叠,并且缓冲区大小适当。
because the standard of is that the behaviour (if not the exact implementation) of std::copy
is equivalent to: 因为标准是
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;
}
}
which means it copies member-by-member, incrementing each iterator and returns the next write position in the output. 这意味着它逐个成员地复制,递增每个迭代器并返回输出中的下一个写入位置。
This is not the same behaviour as memcpy which is what you actually want here. 这与memcpy的行为不同,这是您实际上想要的。 There is nothing wrong with using memcpy (even if a certain Microsoft compiler tells you it is unsafe, which it can be but so is driving a truck if you don't drive it properly, that doesn't mean nobody can ever drive one).
使用memcpy并没有错(即使某个Microsoft编译器告诉您它是不安全的,也可能是不安全的,但是如果您没有正确驾驶它,那么驾驶卡车也是如此,这并不意味着没有人可以驾驶一辆) 。
To interpret the vector's contents as raw memory, use reinterpret_cast
to unsigned char *
: 要将向量的内容解释为原始内存,请使用
reinterpret_cast
将unsigned char *
:
std::copy(reinterpret_cast<unsigned char *>(&*vData.begin()),
reinterpret_cast<unsigned char *>(&*vData.end()), szBuffer);
You need to indirect and take the address of the begin and end elements because it is not guaranteed that vector::iterator
is a pointer type. 您需要间接获取begin和end元素的地址,因为不能保证
vector::iterator
是指针类型。
This is one of the few guaranteed safe uses of reinterpret_cast
. 这是保证对
reinterpret_cast
安全使用的少数几个方法之一。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.