Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A more elegant way to use recv() and vector<unsigned char>

Tags:

c++

stl

vector

recv

So far, I have this code sample:

...
int nbytes =0;
vector<unsigned char> buffer;
buffer.resize(5000);
nbytes = recv(socket, &buffer[0], buffer.size(),0);
//since I want to use buffer.size() to know data length in buffer I do
...
buffer.resize(nbytes);

Is it some another way, to know data length in buffer without using resize() twice? Because it is not possible to receive data into vector that is not resized to proper size. I think reserve() method don't do allocation, according to the C++ STL documentation. And another question: is using this kind of technique is memory leak-safe ?

like image 784
Hitman_99 Avatar asked Nov 19 '10 09:11

Hitman_99


4 Answers

There is not much you can do, you cannot know the post size before the recv call.

Some cleanup:

std::vector<unsigned char> buffer(5000);
int result = recv(socket, buffer.data(), buffer.size(), 0);
if (result != -1) {
   buffer.resize(result);
} else {
   // Handle error
}
like image 200
ronag Avatar answered Nov 12 '22 13:11

ronag


This technique is leak-safe, quite clean and preferable. Using std::vector is the recommended way of implementing a variable-length buffer in C++.

If you find that not all data fits into the vector - no problem, just resize it to bigger size and pass the address of the section that follows the already-filled part.

Using reserve() is not a very good idea - it doesn't affect what size() returns, so you will lose convenience and likely will gain no advantages.

like image 39
sharptooth Avatar answered Nov 12 '22 13:11

sharptooth


I don't believe so [a more elegant way?]. Fundamentally, you need to have more than enough characters in the buffer to recv many bytes; then once you've read them, if you want the buffer to only contain the received bytes you need to resize downwards. What you've shown is probably similar to how I would approach things.

You are correct that reserve is not sufficient. You cannot write to elements that don't exist and have only had storage allocated for them in advance.

like image 1
CB Bailey Avatar answered Nov 12 '22 14:11

CB Bailey


This code is fine. The difference between resize and reserve is, that resize changes the value returned by size (and actually creates new default initialized objects), whereas reserve does not (it only allocates more memory).

Depending on how you process the data, you can leave the second resize out, and do it with a loop like this:

for (vector<unsigned char>::iterator it = buffer.begin(); 
     it != buffer.begin() + nbytes; 
     it++) 
{
    // process each byte
}

Thus you can just read the data that was actually written, and ignore the rest. This means you would only set the size of the vector once, and then never change it. In general, as long you only work with iterators, there is no need to resize the vector, as the valid data range will always be [buffer.begin(), buffer.begin() + nbytes).

like image 1
Björn Pollex Avatar answered Nov 12 '22 13:11

Björn Pollex