Boost Asio Buffering and STL Containers – Very Odd to Pre-Fill
I was doing work today with boost asio and the buffering of async socket I/O and was stunned at the realization that the size() was being used in the buffering of data in a std::string or a std::vector<char>. But let me explain.
The standard call to async_receive_from() - or, in fact, any boost async reader method, is a boost::asio::buffer. This is a standard buffer class for boost that takes an underlying data container - like a char [] or a std::string oe a std::vector<char> and then populates that underlying data container with the data coming from the source - be that UDP or TCP, and it works very nicely.
But what I expected was to do something like the following:
std::vector<char> buff; buff.reserve(16384); ... mSocket.async_receive_from(boost::asio::buffer(buff), boost::bind(...);
such that I had created (allocated) 16kB of space in the std::vector<char> and then when I got the callback, I'd look at size() and see what was really in there. But that's not how it works.
If you do that, then nothing will be read in to the buffer because boost uses the size() to know how big the buffer is. This means that you really have to "pre-fill" the container with junk, and then let the boost asio methods overwrite the junk with good data. It's then mandatory that you get the number of bytes read from boost, as there's no way for you to know what's in the container that's from the I/O and what was put there by you prior to the call.
The code looks deceptively simple:
std::vector<char> buff(16384); ... mSocket.async_receive_from(boost::asio::buffer(buff), boost::bind(...);
and in many cases, the value in the constructor might appear to be a capacity. But it's really a size of junk data. Very odd.
Given that boost chose to use size() versus capacity(), I have to wonder why. It makes no sense to me at all. But hey... it's not the first, and it sure won't be the last.