A dynamic buffer type in C++?
std::vector<unsigned char> buffer;
Every push_back will add new char at the end (reallocating if needed). You can call reserve to minimize the number of allocations if you roughly know how much data you expect.
buffer.reserve(1000000);
If you have something like this:
unsigned char buffer[1000];
std::vector<unsigned char> vec(buffer, buffer + 1000);
One more vote for std::vector. Minimal code, skips the extra copy GMan's code do:
std::vector<char> buffer;
static const size_t MaxBytesPerRecv = 1024;
size_t bytesRead;
do
{
const size_t oldSize = buffer.size();
buffer.resize(oldSize + MaxBytesPerRecv);
bytesRead = receive(&buffer[oldSize], MaxBytesPerRecv); // pseudo, as is the case with winsock recv() functions, they get a buffer and maximum bytes to write to the buffer
myData.resize(oldSize + bytesRead); // shrink the vector, this is practically no-op - it only modifies the internal size, no data is moved/freed
} while (bytesRead > 0);
As for calling WinAPI functions - use &buffer[0] (yeah, it's a little bit clumsy, but that's the way it is) to pass to the char* arguments, buffer.size() as length.
And a final note, you can use std::string instead of std::vector, there shouldn't be any difference (except you can write buffer.data() instead of &buffer[0] if you buffer is a string)
std::string
would work for this:
- It supports embedded nulls.
- You can append multi-byte chunks of data to it by calling
append()
on it with a pointer and a length. - You can get its contents as a char array by calling
data()
on it, and the current length by callingsize()
orlength()
on it. - Freeing the buffer is handled automatically by the destructor, but you can also call
clear()
on it to erase its contents without destroying it.
You want a std::vector
:
std::vector<char> myData;
vector
will automatically allocate and deallocate its memory for you. Use push_back
to add new data (vector
will resize for you if required), and the indexing operator []
to retrieve data.
If at any point you can guess how much memory you'll need, I suggest calling reserve
so that subsequent push_back
's won't have to reallocate as much.
If you want to read in a chunk of memory and append it to your buffer, easiest would probably be something like:
std::vector<char> myData;
for (;;) {
const int BufferSize = 1024;
char rawBuffer[BufferSize];
const unsigned bytesRead = get_network_data(rawBuffer, sizeof(rawBuffer));
if (bytesRead <= 0) {
break;
}
myData.insert(myData.end(), rawBuffer, rawBuffer + bytesRead);
}
myData
now has all the read data, reading chunk by chunk. However, we're copying twice.
We instead try something like this:
std::vector<char> myData;
for (;;) {
const int BufferSize = 1024;
const size_t oldSize = myData.size();
myData.resize(myData.size() + BufferSize);
const unsigned bytesRead = get_network_data(&myData[oldSize], BufferSize);
myData.resize(oldSize + bytesRead);
if (bytesRead == 0) {
break;
}
}
Which reads directly into the buffer, at the cost of occasionally over-allocating.
This can be made smarter by e.g. doubling the vector size for each resize to amortize resizes, as the first solution does implicitly. And of course, you can reserve()
a much larger buffer up front if you have a priori knowledge of the probable size of the final buffer, to minimize resizes.
Both are left as an exercise for the reader. :)
Finally, if you need to treat your data as a raw-array:
some_c_function(myData.data(), myData.size());
std::vector
is guaranteed to be contiguous.