In C++ 11, what is the best way to perform the following code:
// definitions
vector<char> rcvbuf;
struct somethingParams
{
char Magic[4];
int Version;
int MsgID;
int MsgLen;
};
Code:
struct somethingParams mParams;
memcpy(&mParams, rcvbuf.data(), sizeof(somethingParams));
rcvbuf.erase(rcvbuf.begin(), rcvbuf.begin + sizeof(somethingParams));
From what I've read, memcpy is not recommended in C++. I understand that it is "C-style". Is there a better way to achieve what I am doing above? (ie. Copying data from a vector into a struct.)
Just see-ing if I can make it more "C++".
Thanks.
memcpy
is kosher in C++. Of course it should not be used to make a copy of an array (we have std::copy
for that, as well as vectors and other fun things) but the case of initializing a struct from binary data is inherently type-unsafe so C++ doesn't give you anything here that C doesn't.
You must, however, remember to use memcpy
only with trivially copyable types. You can use a static_assert
to make sure you don't run afoul of this rule and trigger undefined behaviour.
static_assert(std::is_trivially_copyable<somethingParams>::value,
"somethingParams must be trivially copyable");
Your code is confusing. You have a vector
of char
s (of length n
let's say) on the one hand.
And you have a struct with a char
array of length 4 and three int
s.
I don't see what a blind memcpy
would bring as a reasonable result really.
But maybe I can evoke some thoughts that could help you dig further:
vector
of char
elements could maybe replaced by a string
object? A string
object is meant to hold a char
array internally. I consider this more C++, but depends on your requirements. memcpy
simply copies memory. I am not sure if this is what you want; I reckon the struct contains garbage after the copy. Unpredictable in my opinion. vector
is an STL container) a standard way of doing it in C++ (apart from the aforementioned std::copy
function) is by iterating over the elements and copy them. See below. Most familiar with iterators:
for (vector<char>::iterator it = rcvbuf.begin(); it != rcvbuf.end(); it++) {
//copy element *it into something
}
C++11 introduced auto range for loops:
for (auto elem : rcvbuf) {
//copy element elem into something
}
Further elaboration:
The vector contains 16 elements. The 4th element is the null character to simulate the end of the C style string. Without the null character the char
array would contain garbage too.
I removed the erase
for simplicity. It simply erases the elements in a specified range (by iterators); in your case it simply removes sizeof(somethingParams)
bytes/ char
s from the vector, provided it contains enough elements, otherwise segmentation fault is likely.
See the result below, it's plain nonsense.
char t[] = {'a', 'b', 'c', '\0', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'};
vector<char> rcvbuf(t, t + 16);
struct somethingParams {
char Magic[4] = {'w', 'x', 'y', 'z'};
int Version{99};
int MsgID{99};
int MsgLen{99};
} mParams;
memcpy(&mParams, rcvbuf.data(), sizeof(somethingParams));
//rcvbuf.erase(rcvbuf.begin(), rcvbuf.begin() + sizeof (somethingParams));
cout << "Magic: " << mParams.Magic << endl;
cout << "Version: " << mParams.Version << endl;
cout << "MsgID: " << mParams.MsgID << endl;
cout << "MsgLen: " << mParams.MsgLen << " bytes" << endl;
Result (with int
occupying 4 bytes on my machine):
Magic: abc
Version: 1734763876
MsgID: 1802135912
MsgLen: 1869507948 bytes
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.