当使用对streambuf 进行操作的Boost.Asio 操作或使用streambuf 的流对象(例如std::ostream 和std::istream)时,将正确管理底层输入和输出序列。如果为操作提供缓冲区,例如将prepare() 传递给读操作或将data() 传递给写操作,则必须显式处理commit() 和consume()。
示例中的问题是它违反了 API 约定,导致未初始化的内存被提交给输入序列。 commit() 文档指出:
需要前面调用 prepare(x) where x >= n,并且没有修改输入或输出序列的干预操作。
在prepare() 和commit() 之间使用std::ostream 违反了这个约定,因为它会修改输入序列:
// Prepare 1024 bytes for the output sequence. The input sequence is
// empty.
boost::asio::streambuf streambuf;
streambuf.prepare(1024);
// prepare() and write to the output sequence, then commit the written
// data to the input sequence. The API contract has been violated.
std::ostream ostream(&streambuf);
ostream << "1234567890";
// Commit 10 unspecified bytes to the input sequence. Undefined
// behavior is invoked.
streambuf.commit(10);
这是一个完整的示例 demonstrating 使用带有注释 cmets 的 streambuf:
#include <iostream>
#include <vector>
#include <boost/asio.hpp>
int main()
{
std::cout << "with streams:" << std::endl;
{
boost::asio::streambuf streambuf;
// prepare() and write to the output sequence, then commit the written
// data to the input sequence. The output sequence is empty and
// input sequence contains "1234567890".
std::ostream ostream(&streambuf);
ostream << "1234567890";
// Read from the input sequence and consume the read data. The string
// 'str' contains "1234567890". The input sequence is empty, the output
// sequence remains unchanged.
std::istream istream(&streambuf);
std::string str;
istream >> str;
std::cout << "str = " << str << std::endl;
// Clear EOF bit.
istream.clear();
// prepare() and write to the output sequence, then commit the written
// data to the input sequence. The output sequence is empty and
// input sequence contains "0987654321".
ostream << "0987654321";
// Read from the input sequence and consume the read data. The string
// 'str' contains "0987654321". The input sequence is empty, the output
// sequence remains unchanged.
istream >> str;
std::cout << "str = " << str << std::endl;
}
std::cout << "with streams and manual operations:" << std::endl;
{
boost::asio::streambuf streambuf;
// prepare() and write to the output sequence, then commit the written
// data to the input sequence. The output sequence is empty and
// input sequence contains "1234567890".
std::ostream ostream(&streambuf);
ostream << "1234567890";
// Copy 10 bytes from the input sequence. The string `str` contains
// "1234567890". The output sequence is empty and the input
// sequence contains "1234567890".
auto data = streambuf.data();
std::string str(boost::asio::buffers_begin(data),
boost::asio::buffers_begin(data) + 10);
std::cout << "str = " << str << std::endl;
// Consume 10 bytes from the input sequence. The input sequence is
// now empty.
streambuf.consume(10);
// prepare() and write to the output sequence, then commit the written
// data to the input sequence. The output sequence is empty and
// input sequence contains "0987654321".
ostream << "0987654321";
// Copy 10 bytes from the input sequence. The string `str` contains
// "0987654321. The output sequence is empty and the input
// sequence contains "0987654321".
data = streambuf.data();
str.assign(boost::asio::buffers_begin(data),
boost::asio::buffers_begin(data) + 10);
std::cout << "str = " << str << std::endl;
// Consume 10 bytes from the input sequence. The input sequence is
// now empty.
streambuf.consume(10);
}
}
输出:
with streams:
str = 1234567890
str = 0987654321
with streams and manual operations:
str = 1234567890
str = 0987654321
有关 streambuf 使用的更多信息,请考虑阅读this 答案。