c++ - 使用 boost::asio::streambuf 作为 istream 和数组作为 string_view 是否安全?

标签 c++ boost-asio

例如,如果我使用这样的代码,该缓冲区内的内存工作是否会出现问题?我可以使用输入流并使用具有相同streambuf的sv(string_view)吗?

boost::asio::streambuf buf_;
std::ostream out(&buf_);
int a = 1488;
out << a;
out << 33;
out << 100005l;
std::basic_string_view<uint8_t> arr_ {boost::asio::buffer_cast<const uint8_t *>(buf_.data()), buf_.size()};
std::istream in(&buf_);
int g;
in >> g;
int d = ArrayToValue<int>(&arr_[0]);

既然我希望答案是肯定的,是否会出现问题,如果是这样,在缓冲区已满之前不会使用 string_view 吗?也就是说,在填充并从该缓冲区读取之后,将其与输入流一起使用!

最佳答案

streambuf::data()返回一个缓冲区序列。所以不能保证你有string_view一般来说,绘制其全部容量。

The basic_streambuf class is derived from std::streambuf to associate the streambuf's input and output sequences with one or more character arrays.

但是,文档继续提到

The basic_streambuf class's public interface is intended to permit the following implementation strategies:

  • A single contiguous character array, which is reallocated as necessary to accommodate changes in the size of the character sequence. This is the implementation approach currently used in Asio.
  • A sequence of one or more character arrays, where each array is of the same size. Additional character array objects are appended to the sequence to accommodate changes in the size of the character sequence.
  • A sequence of one or more character arrays of varying sizes. Additional character array objects are appended to the sequence to accommodate changes in the size of the character sequence.

(已添加突出显示)

所以,如果你断言了你的假设,那么你现在可能会逃脱惩罚:

assert(buf_.data().begin() + 1 == buf_.data().end());
auto first = *buf_.data().begin();

std::basic_string_view<uint8_t> arr_(   //
    buffer_cast<const uint8_t*>(first), //
    first.size());

但是,一旦您使用std::istream在streambuf对象上,它将执行 调用basic_stream_buf::consume() ,它没有明确记录这一点 它不会重新分配。

但是,此模型的 DynamicBuffer_v1 概念 documents :

<表类=“s-表”> <标题> x.consume(n) 从输入序列的开头删除 n 个字节。如果 n 大于输入序列的大小,
则删除整个输入序列。之前使用data() 或prepare() 获得的所有常量或可变缓冲区
序列均无效。

因此,为了遵循库模式,似乎最好不要依赖于 string_view阅读 istream 后保持有效.

另请注意,最好限制 istream 的范围/ostream对象:

boost::asio::streambuf buf_;
{
    std::ostream out(&buf_);
    int a = 1488;
    out << a;
    out << 33;
    out << 100005l;
}

assert(buf_.data().begin() + 1 == buf_.data().end());
auto first = *buf_.data().begin();

std::basic_string_view<uint8_t> arr_(   //
    buffer_cast<const uint8_t*>(first), //
    first.size());

{
    std::istream in(&buf_);
    int g;
    in >> g;
}

或者甚至:

int const a = 1488;

boost::asio::streambuf buf_;
std::ostream(&buf_) << a << 33 << 100005l;

assert(buf_.data().begin() + 1 == buf_.data().end());
auto first = *buf_.data().begin();

std::basic_string_view<uint8_t> arr_(   //
    buffer_cast<const uint8_t*>(first), //
    first.size());

int g;
std::istream(&buf_) >> g;

更新

根据以下发现,有一种比上述所有策略更快的策略 评论:const_buffers_1奇怪的是,里氏可替代单个 缓冲。您可以让编译器检查这一点:

asio::const_buffer const& first = buf_.data();

如果 Asio 的 future 版本更改了实现,则无法编译 战略。请注意,最近您应该更喜欢拼写缓冲区类型 BOOST_ASIO_CONST_BUFFERBOOST_ASIO_MUTABLE_BUFFER相反,所以你的代码 不依赖于 BOOST_ASIO_NO_DEPRECATED 的配置.

<强> Live On Coliru

#include <boost/asio.hpp>
namespace asio = boost::asio;

int main() {
    asio::streambuf sb;
    sb.commit(asio::buffer_copy(sb.prepare(32), asio::buffer("Hello World!", 12)));

    asio::BOOST_ASIO_CONST_BUFFER const& first = sb.data(); // proves single buffer assumption
    assert(first.size() == 12);
}

关于c++ - 使用 boost::asio::streambuf 作为 istream 和数组作为 string_view 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72236319/

相关文章:

c++ - std::remove_cv 应该在 const T 数组上产生什么类型?

c++ - 我需要清理非指针数据成员吗?

c++ - 使用 boost::asio::generic::raw_protocol::socket 时 OS (Linux) 不添加第 2 层 header

c++ - boost asio - session 线程不会结束

c++ - 在 boost 中将安全套接字作为普通套接字传递

tcp - 异步接收是否保证连接失败的检测?

c++ - 生成一组随机 x、y、z 数,它们之间的差异在定义的限制之间最小

c++ - 如何包含 std :list in a (C++) constructors parameter list?

python - 通过 Cython(回调)将 Python 函数应用于 std::vector

c++ - 如何使用 Boost.Asio 的生成(堆栈协程),使其仅依赖于 Boost.Context?