Reputation: 243
With C buffer, I often do like this:
BYTE buffer[MAX_SIZE];
int dataSize = 0;
while (appRunning())
{
dataSize += Receive(buffer + dataSize, MAX_SIZE - dataSize);
int processedSize = ProcessBuffer(buffer, dataSize);
ASSERT(processedSize <= dataSize);
dataSize -= processedSize;
memmove(buffer, buffer + processedSize, dataSize);
};
Is it possible to do so with a std::vector
without losing much performance?
EDIT:
I have found a way to replace a raw C buffer by a std::vector
.
std::vector<BYTE> vbuf;
vbuf.reserve(MAX_SIZE); // allocated at once
while (appRunning())
{
int pendingSize = GetPendingDataSize(); // from a socket
if (pendingSize > vbuf.capacity())
pendingSize = vbuf.capacity();
vbuf.resize(pendingSize);
int recvSize = Receive(vbuf.data(), vbuf.size());
ASSERT(recvSize < vbuf.size());
int processedSize = ProcessBuffer(vbuf.data(), vbuf.size());
std::rotate(vbuf.begin(), vbuf.begin() + processedSize, vbuf.end());
vbuf.resize(vbuf.size() - processedSize);
};
Actually, in my practical usage, receiving data and processing data may be done in multithread. So by using vector, I do not need to manage buffer's allocation, data size and buffer capacity manually.
Compares to the C buffer, the performance penalty here is at vbuf.resize()
calls. But I think that penalty is insignificant.
Any better way is appreciated.
Upvotes: 6
Views: 4014
Reputation: 1005
If you want behavior similar to C (that is, you want to guarantee the vector won't ever free or allocate more memory for the underlying vector), a nice solution is to use Boost's static_vector. It statically allocates the underlying buffer but otherwise it acts like a normal vector.
boost::static_vector<BYTE, MAX_SIZE> buffer;
For this type of activity, however, you might also look into std::queue or boost::cirular_buffer and see if one of those fits your needs.
Upvotes: 0
Reputation: 62686
It's perfectly possible to replace it with std::vector
, or equivalently std::array
. You don't need to resize the vector, so don't.
std::vector<BYTE> buffer(MAX_SIZE);
BYTE * start = buffer.data();
int dataSize = 0;
while (appRunning())
{
dataSize += Receive(start, MAX_SIZE - dataSize);
int processedSize = ProcessBuffer(buffer.data(), dataSize);
ASSERT(processedSize <= dataSize);
dataSize -= processedSize;
start = std::copy_n(buffer.data() + processedSize, dataSize, buffer.data());
};
Upvotes: 0
Reputation: 136246
When receiving messages over a TCP connection the last message in the buffer may be incomplete. After processing complete messages, people often just memmove
that last incomplete message to the beginning of the buffer.
Another strategy is to use a "smart" ring-buffer to avoid that memmove
and also avoid data wrapping over the ring buffer thus creating discontinuity. To make a "smart" ring-buffer allocate memory for the buffer using mmap
and map the same region of pages twice with no gaps in between. This way reading past the end of the buffer continues reading it from the start, preventing the discontinuity inherent when using a regular ring-buffer.
Using std::vector
for network buffers is less than ideal because resizing a vector initialises its elements that are later overwritten by recv
call. That initialization is unnecessary for such buffers.
Upvotes: 2
Reputation: 43969
Since C++11, C arrays have been for the most parts replaced by std::array:
std::array<BYTE, MAX_SIZE> buffer;
It is only a thin wrapper around C arrays. So, from a performance perspective, you do not loose anything. There are nicer to work with, however.
But like C arrays, they only work for fixed-time arrays where the size is known at compile time. It is not possible to resize them. But if I read your question correctly, you do not need that extra flexibility, here.
Upvotes: 1
Reputation: 89
Writing from memory, please check if it works for you:
std::vector<BYTE> buffer;
buffer.reserve(MAX_SIZE);
int dataSize = 0;
while (appRunning())
{
dataSize += Receive(&buffer[0] + dataSize, MAX_SIZE - dataSize);
int processedSize = ProcessBuffer(&buffer[0], dataSize);
ASSERT(processedSize <= dataSize);
dataSize -= processedSize;
memmove(&buffer[0], &buffer[0] + processedSize, dataSize);
};
Upvotes: -1