设置标准流使用的内部缓冲区(pubsetbuf)

时间:2009-09-29 18:30:41

标签: c++ visual-c++ stream

我正在编写一个需要将数据写入现有缓冲区的子程序,我想使用stringstream类来简化数据的格式化。

最初,我使用以下代码将流的内容复制到缓冲区中,但是希望避免使用此解决方案,因为它会复制太多数据。

#include <sstream>
#include <algorithm>

void FillBuffer(char* buffer, unsigned int size)
{
    std::stringstream message;
    message << "Hello" << std::endl;
    message << "World!" << std::endl;

    std::string messageText(message.str());
    std::copy(messageText.begin(), messageText.end(), buffer);
}

这是我发现streambuf::pubsetbuf()方法的时候,只需重写上面的代码如下。

#include <sstream>

void FillBuffer(char* buffer, unsigned int size)
{
    std::stringstream message;
    message.rdbuf()->pubsetbuf(buffer, size);

    message << "Hello" << std::endl;
    message << "World!" << std::endl;
}

不幸的是,这在Visual Studio 2008附带的C ++标准库实现下不起作用; buffer保持不变。

我查看了pubsetbuf的实现,结果发现它确实“什么都不做”。

virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
{   // offer buffer to external agent (do nothing)
    return (this);
}

这似乎是给定C ++标准库实现的限制。配置流以将其内容写入给定缓冲区的推荐方法是什么?

3 个答案:

答案 0 :(得分:19)

经过对此问题的更多研究以及对我的代码的详细审查后,我发现a post建议使用手动编码的std::streambuf类。这段代码背后的想法是创建一个streambuf来初始化其内部以引用给定的缓冲区。代码如下。

#include <streambuf>

template <typename char_type>
struct ostreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> >
{
    ostreambuf(char_type* buffer, std::streamsize bufferLength)
    {
        // set the "put" pointer the start of the buffer and record it's length.
        setp(buffer, buffer + bufferLength);
    }
};

现在,如果你看my original code,你会注意到我真的不需要stringstream开头。我真正需要的是使用IOStream库写入外部缓冲区的方法,std::ostream是解决此问题的更好的类型。顺便说一句,我怀疑这是array_sink Boost.IOStreams类型的实现方式。

以下是使用我的ostreambuf类型的修改后的代码。

#include <ostream>
#include "ostreambuf.h"  // file including ostreambuf struct from above.

void FillBuffer(char* buffer, unsigned int size)
{
    ostreambuf<char> ostreamBuffer(buffer, size);
    std::ostream messageStream(&ostreamBuffer);

    messageStream << "Hello" << std::endl;
    messageStream << "World!" << std::endl;
}

答案 1 :(得分:4)

看起来像(正式弃用,但仍然是标准的)std::strstream的工作。您还可以查看Boost.IOStreams库,特别是array_sink

答案 2 :(得分:1)

正如您发布的链接所说:“具体实施可能会有所不同”。

你能不能简单地返回std :: string对象,然后在需要char缓冲区时使用std :: string :: c_str()或std :: string :: data()?

或者从C库中使用sprintf(),然后可以在传递的缓冲区中完成整个操作。由于这种方式可能导致潜在的缓冲区溢出,并且您使用的是Visual C ++,您可能会考虑sprintf_s