简体   繁体   中英

Copying from vector into a struct in C++ 11

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:

  1. A 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.
  2. 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.
  3. To copy from a container (a 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM