Boost.Format能否与预先分配的缓冲区一起使用?

7
我想知道Boost.Format是否支持使用固定宽度/预分配缓冲区作为输出,而不是由库自己管理的动态缓冲区?
也就是说,通常您会这样做:
boost::format myfmt("arg1: %1% / arg2: %2%");
// e.g.:
cout << (myfmt % 3.14 % 42);
// or
string s = boost::str( myfmt % "hey!" % "there!");

所以Boost:Format库会自动分配足够的空间并为您管理“输出缓冲区”。我想知道是否有办法在Boost.Format中使用预定义的非动态缓冲区,例如:
const size_t buf_sz = 512;
char big_enough[buf_sz];
boost::format myfmt("arg1: %1% / arg2: %2%");
myfmt.attach_buffer(big_enough, buf_sz);
myfmt % "hey!" % "there!"
// big_enough buffer now contains the result string

我知道我可以浏览示例、文档和源代码,但除了现在缺少时间(可能会错过一些东西),还有一个有趣的问题需要解决:如果不可能,如果有具体的原因,有人能解释一下吗?——这是故意的吗?它是否与API匹配?......?

免责声明:此问题不涉及性能!


当您的空间用尽时,您希望发生什么?对于固定缓冲区,我会使用snprintf,但这只是我的个人偏好 :) - nhed
如果不适合,库可以选择抛出异常或者停止填充缓冲区(类似于已经可用的选项)。 - Martin Ba
我不确定那些异常是否适用于目标缓冲区。 - nhed
1个回答

5

初始想法

源代码来看,似乎你可以使用自己的分配器,然后由boost::format的内部流(internal_streambuf_t)使用。这对你的情况是否足够好呢?

例如,你可以使用类似于libstdc++ array_allocator的东西。

不幸的是,boost::format还使用了一些不使用自定义分配器的std::vector,这可能会成为你的问题所在?

boost::format如何工作

我查看了boost::format的源代码,以下是它的工作原理(下面描述了str()<<调用str()或使用标准的std::ostream内容):

  • 格式类将所有参数和格式字符串分开存储,有时使用自定义分配器,有时使用默认分配器。
  • 调用str()时,它会创建一个新的std::string,并使用自定义分配器使其足够大以容纳结果。
  • 然后,它将从格式字符串中附加所有参数和静态字符串片段到结果字符串中。
  • 最后,它通过值返回结果字符串。

因此,最终的结果字符串不是存储在格式类内部的,而是在需要时创建的。

因此,即使您可以在使用自定义分配器时找到结果字符串的位置,在调用str()期间/之后才能访问它。这就解释了为什么不可能:格式化的结果永远不会存储在类的“输出缓冲区”内。

为什么会这样工作

我不知道为什么他们这样做。我认为这是因为只有在知道所有参数后才能构建结果,将结果存储起来会浪费空间,并且对于给定的格式/参数组合,通常只需要结果一次。因此,在需要时创建它不会导致额外的工作,因为通常只调用一次str()

解决方案

  • 创建一个固定缓冲区,将str()<<的结果包装起来,并将其复制到缓冲区中
  • 使用stream_buffer将字符串“流式”传输到缓冲区中(见下面的示例)
  • 继承该类并添加自己的str()函数,该函数将结果存储在固定的缓冲区中。

使用boost::iostreams进行可能的解决方案(已测试):

#include <iostream>
#include <boost/format.hpp>
#include <boost/iostreams/stream.hpp>

int main()
{
    char buffer[100];

    boost::iostreams::stream<boost::iostreams::array_sink>
        stream(buffer, sizeof(buffer));

    stream << (boost::format("arg1 = %1%") % 12.5);
    stream << '\0';  // make sure buffer contains 0-terminated string

    std::cout << buffer << std::endl;    
}

有用的信息。我认为分配器的一个小问题是它们只能通过bad_alloc来报告失败,对吗? - Martin Ba
@Martin:我认为你是对的。此外,我查看了格式的源代码,我认为使用分配器很难做到。我已经更新了我的答案,并附上了我发现的内容。 - rve
干得好!我理解的对吗:每次调用.str()时,输出字符串都会重新构建? - Martin Ba
@Martin:是的,每次调用str()时,输出字符串都会被重新构建。 - rve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接