std::字符串流,直接输出缓冲区/字符串结果访问,避免复制
std::stringstream with direct output buffer / string result access, avoiding copy?
是否存在std::stringstream
的规范/公共/免费实现变体,其中我每次调用str()
时都不支付完整字符串副本的费用?(可能是通过在osteam类中提供直接c_str()
成员?)
我在这里发现了两个问题:
- C++stl字符串流直接缓冲区访问(是的,它基本上是相同的标题,但请注意,它的公认答案根本不适合这个问题。)
- 从std::string流而不进行复制?(同样,公认的答案与此问题不匹配。)
当然,不推荐使用的std::strstream
类确实允许直接访问缓冲区,尽管它的接口非常古怪(除了不推荐使用之外)。
似乎还可以找到几个代码示例来解释如何自定义std::streambuf
以允许直接访问缓冲区——我在实践中没有尝试过,但它似乎很容易实现。
我的问题实际上有两个方面:
- 为什么
std::[o]stringstream
(或者更确切地说,basic_stringbuf
)不允许直接访问缓冲区,而只允许通过整个缓冲区的(昂贵的)副本进行访问,还有什么更深层次的原因吗 - 考虑到实现这一点似乎很容易,但并不是微不足道的,是否有任何通过boost或其他来源提供的varaint可以封装此功能
注意:str()
制作的副本的性能命中率非常可测量(*),所以当I迄今为止看到的用例真的never需要从字符串流返回副本时,必须为此付费似乎很奇怪。(如果我需要一份副本,我总是可以在"客户端"制作。)
(*):使用我们的平台(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());
因此,使用std::string
和+=
(显然只有当我不需要自定义/数字格式时才有效)比流版本快40%,据我所知,这只是由于str()
制作了完全多余的副本。
我将尝试为我的第一个子弹提供答案
std::ostringstream
不允许直接缓冲区访问有什么更深层次的原因吗
看看streambuf
/stringbuf
是如何定义的,我们可以看到缓冲区字符序列不是以NULL结尾的。
据我所见,提供直接只读缓冲区访问的(假设的)const char* std::ostringstream::c_str() const;
函数只有在有效缓冲区范围始终以NULL结尾时才有意义——即(我认为)sputc始终确保在插入的字符之后插入一个终止的NULL。
我不认为这本身是一个技术障碍,但考虑到basic_streambuf
接口的复杂性,我完全不确定它是否在所有情况下都是正确的。
至于第二个子弹
考虑到实现这一点似乎很容易,但并非微不足道通过boost或其他来源提供的任何变体功能?
这里有Boost.Iotstreams,它甚至包含了一个如何用字符串实现(o)流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();
}
};
在我所做的测试中,将其与c_str()
助手一起使用的运行速度略快于复制str().c_str()
版本的普通ostringstream
。
我不包括测量代码。这个领域的性能非常脆弱,一定要自己衡量你的用例!(例如,字符串流的构造函数开销是不可忽略的。)
- 为什么没有访问所有字符串字符?
- 使用 ReadProcessMemory 获取字符串值的访问冲突
- 循环访问还包含未使用元素的字符串数组
- 循环访问资源字符串表
- 在qt创建器中调试时如何访问字符串变量的完整值?
- 当我用"ñ"字符循环访问字符串时出现奇怪的结果
- 如何在读取文件时访问以前的字符串?
- C++字符串问题-如何访问字符串元素
- 访问包含P的有效索引时返回空格的C++字符串
- 交换两个字符串时访问正确的内存时,我遇到了分段错误
- C++/CLI访问字符串::来自非CLI代码的格式
- 需要从字符串数组的一部分访问元素
- 是否可以从字符串访问变量?
- 循环访问 c++ 中的字符串
- 循环访问字符串片段
- 如何修复访问动态数组中结构中的字符串变量时"segmentation fault (core dumped)"错误
- 如何在 Qt/C++ 中仅将文件路径作为字符串访问文件
- C 使用字符串访问变量
- 基于字符串访问类成员
- 动态 C 字符串访问