如果您不在派生的 class 实现中这样做,`basic_streambuf` 会创建自己的 get/put 区域吗?

Does `basic_streambuf` create its own get/put areas if you don't do it in a derived class implementation?

我已经多次看到有关创建自定义流缓冲区的说明:您需要做的就是在 [= 的后代中正确实现 overflowunderflowpbackfail 18=] 并且您可以创建一个使用它来格式化数据的流。这三个例程定义了自定义流的 'controlled sequence'。

但是std::basic_streambuf的受保护成员列表中还潜伏着其他怪物,即setgsetp。这些为输入和输出设置缓冲区。获取和设置数据的 public 成员尝试先访问这些区域,然后再执行受控序列。

对于几个不同的自定义流缓冲区,如果流设置自己的 get/put 区域,则可能会出现问题。所以我希望这样的 streambufs 避免使用 get/put 区域和 always 使用 overflow, underflow , 和 pbackfail 没有任何中间缓冲。

对于一个天真的简化示例,如果您正在包装另一个 streambuf,underflow 的实现可能如下所示:

template <class C, class TR>
typename TR::int_type wrapping_streambuf<C, TR>::underflow()
{
 return m_wrapped_streambuf->sgetc();
}

让包装的 streambuf 处理所有脏工作。 这是另一个计算行数的简单示例:

template <class C, class TR>
typename TR::int_type tracking_streambuf<C, TR>::uflow()
{
  auto rv = m_wrapped_streambuf->sbumpc();
  if (rv == (TR::int_type)'\n') ++ m_input_line_count;
  return rv;
}

对于此类流,setg 没有有用的实现,因为您无法访问包装缓冲区的内部获取区域。对于 tracked_streambuf,强加 get/put 区域会使计数线无法与流的逻辑顺序同步。

我认为答案是 永远不要在后代 类 中调用 setgsetp。事实上,他们可能应该覆盖 setgsetpgbumppbump 以抛出异常。

查看 <streambuf> header 我看到自定义 streambuf 如果我这样做,在我最喜欢的库实现中可能会按我想要的方式工作(有 null gptr/pptr 的检查)。但这是保证吗?

std::basic_streambuf的默认构造函数将定义get和put区域的六个指针设置为空指针值,因此默认不会"create its own get/put area"。

函数setgsetpgbumppbump是受保护的成员,默认情况下不会被public成员函数调用,所以你不必担心他们。当然,覆盖它们抛出异常也不错。

此外,没有中间缓冲区的自定义流缓冲区 class 也应覆盖 uflow function, which may be invoked by public member functions to handle overflow cases where the value of the get pointer is required to be advanced. By default, its default behavior is (quoted from [streambuf.virt.get]/16):

Default behavior: Calls underflow(). If underflow() returns traits​::​eof(), returns traits​::​eof(). Otherwise, returns the value of traits​::​to_­int_­type(*gptr()) and increment the value of the next pointer for the input sequence.

因此,如果您不重写此函数,则会导致通过空指针进行间接访问的未定义行为。