std :: stringstream与直接输出缓冲区/字符串结果访问,避免复制?

Mar*_* Ba 6 c++ iostream stl stringstream

是否存在规范/公共/免费实现变体,std::stringstream每次调用时我都不会为完整的字符串副本付费str()?(可能通过c_str()在骨科中提供直接成员?)

我在这里发现了两个问题:

并且"当然"不推荐使用的std::strstream类确实允许直接缓冲区访问,尽管它的界面非常古怪(除了它被弃用).

似乎人们可以找到几个代码示例来解释如何自定义std::streambuf以允许直接访问缓冲区 - 我没有在实践中尝试过,但它似乎很容易实现.

我的问题实际上是两个方面:

  • 有没有更深层次的原因std::[o]stringstream(或者更确切地说,basic_stringbuf)不允许直接缓冲区访问,而只能通过整个缓冲区的(昂贵)副本进行访问?
  • 鉴于实现这一点似乎很容易,但并非微不足道,是否有任何通过boost或其他来源提供的varaint,包装此功能?

注意:副本的性能损失str()非常可测量的(*),因此当到目前为止看到的用例实际上不需要从stringstream返回的副本时,必须为此付费似乎很奇怪.(如果我需要副本,我总是可以在"客户端"进行.)


(*):使用我们的平台(VS 2005),我在发布版本中测量的结果是:

// tested in a tight loop:

// variant stream: run time : 100%
std::stringstream msg;
msg << "Error " << GetDetailedErrorMsg() << " while testing!";
DoLogErrorMsg(msg.str().c_str());

// variant string: run time: *** 60% ***
std::string msg;
((msg += "Error ") += GetDetailedErrorMsg()) += " while testing!";
DoLogErrorMsg(msg.c_str());
Run Code Online (Sandbox Code Playgroud)

所以使用std::stringwith +=(显然只有在我不需要自定义/数字格式时才能工作,比流版本快40%,据我所知,这只是由于完整的多余副本所str()造成的.

Mar*_* Ba 1

至于第二颗子弹

鉴于实现这一点似乎很容易,但并非微不足道,是否有通过 boost 或其他来源提供的任何变体来封装此功能?

Boost.Iostreams 它甚至包含如何使用字符串实现 (o)stream Sink 的示例。

我想出了一个小测试实现来衡量它:

#include <string>
#include <boost/iostreams/stream.hpp>
#include <libs/iostreams/example/container_device.hpp> // container_sink

namespace io = boost::iostreams;
namespace ex = boost::iostreams::example;
typedef ex::container_sink<std::wstring> wstring_sink;
struct my_boost_ostr : public io::stream<wstring_sink> {
    typedef io::stream<wstring_sink> BaseT;
    std::wstring result;
    my_boost_ostr() : BaseT(result)
    { }

    // Note: This is non-const for flush.
    // Suboptimal, but OK for this test.
    const wchar_t* c_str() {
        flush();
        return result.c_str();
    }
};
Run Code Online (Sandbox Code Playgroud)

在我所做的测试中,使用它的c_str()帮助程序比正常的ostringstream复制str().c_str()版本运行得稍快一些。

我不包括测量代码。这方面的性能非常脆弱,请务必亲自衡量您的用例!(例如,字符串流的构造函数开销是不可忽略的。)