Recently I have been trying to update some code to utilise the standard C++ library functions rather than old C style functions. 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. 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 ?
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 is ignorant, that's what you want.
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]. One way to overcome this type mismatch is to cast that szBuffer to an int*:
std::copy(vData.begin(),vData.end(),reinterpret_cast<int*>(szBuffer));
That reinterpret_cast is a personal preference issue. 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. I (and my project manager overlords) can grep for reinterpret_cast.
The potential for UB here is real as there is no guarantee that this cast is valid due to alignment issues.
Note also that there is no guarantee that std::copy will ever be implemented via memcpy or 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. (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.)
The only reason to switch from std::memcpy to std::copy here is aesthetics. Sometimes aesthetics get in the way. "Foolish consistency is the hobgoblin of small minds." I recommend sticking with 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With