我应该预分配 std::stringstream 吗?
我广泛使用 std::stringstream 在我的应用程序中构造字符串和错误消息。 stringstreams 通常是生命周期非常短的自动变量。
这样的使用会导致每个变量的堆重新分配吗?我应该从临时变量切换到类成员 stringstream
变量吗?
在后一种情况下,如何保留 stringstream 缓冲区? (我应该用足够大的字符串初始化它还是有更优雅的方法?)
I use std::stringstream
extensively to construct strings and error messages in my application. The stringstreams
are usually very short life automatic variables.
Will such usage cause heap reallocation for every variable? Should I switch from temporary to class-member stringstream
variable?
In latter case, how can I reserve stringstream
buffer? (Should I initialize it with a large enough string or is there a more elegant method?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您是否对您的执行情况进行了分析,并发现它们是导致速度缓慢的原因?
考虑它们的用法。它们主要是针对代码正常流程之外的错误消息吗?
至于保留空间......
某些实现可能会在为字符串流进行任何分配之前保留一个小缓冲区。 std::string 的许多实现都是这样做的。
另一种选择可能是(未经测试!)
您可能会在此 gamedev 中找到更多想法线程。
编辑:
使用stringstream的rdbuf可能会也算是一个解决办法。不过,这种方法可能很容易出错,因此请确保这是绝对必要的。绝对不优雅或简洁。
Have you profiled your execution, and found them to be a source of slow down?
Consider their usage. Are they mostly for error messages outside the normal flow of your code?
As far as reserving space...
Some implementations probably reserve a small buffer before any allocation takes place for the stringstream. Many implementations of std::string do this.
Another option might be (untested!)
You might find some more ideas in this gamedev thread.
edit:
Mucking around with the stringstream's rdbuf might also be a solution. This approach is probably Very Easy To Get Wrong though, so please be sure it's absolutely necessary. Definitely not elegant or concise.
缺点
这是一个老问题,但即使从
Visual Studio 2019
中的 C++1z/C++2a 开始,stringstream
也没有保留缓冲区的理想方法。这个问题的其他答案根本不起作用,原因如下:
在空字符串上调用reserve会产生一个空字符串,因此
stringstream
构造函数不需要分配来复制该字符串的内容。stringstream
上的seekp
似乎仍然是未定义的行为和/或不执行任何操作。好的
此代码段按预期工作,
ss
已按照请求的大小进行了预分配。该代码也可以写成一行
std::stringstream ss(std::string(reserve, '\0'));
。丑陋的地方
在此代码段中真正发生的情况如下:
dummy
预先分配了预留空间,并且缓冲区随后填充了空字节(构造函数所需)。stringstream
是用 dummy 构造的。这会将整个字符串的内容复制到预先分配的内部缓冲区中。dummy
被清除,然后被擦除,释放其分配。这意味着为了预分配 stringstream,需要进行两次分配、一次填充和一次复制。最糟糕的是,在表达式过程中,所需的分配需要两倍的内存。哎呀!
对于大多数用例,这可能根本不重要,可以采取额外的填充和复制命中来减少重新分配。
The Bad
This is an old question, but even as of C++1z/C++2a in
Visual Studio 2019
,stringstream
has no ideal way of reserving a buffer.The other answers to this question do not work at all and for the following reasons:
calling reserve on an empty string yields an empty string, so
stringstream
constructor doesn't need to allocate to copy the contents of that string.seekp
on astringstream
still seems to be undefined behavior and/or does nothing.The Good
This code segment works as expected, with
ss
being preallocated with the requested size.The code can also be written as a one-liner
std::stringstream ss(std::string(reserve, '\0'));
.The Ugly
What really happens in this code segment is the following:
dummy
is preallocated with the reserve, and the buffer is subsequently filled with null bytes (required for the constructor).stringstream
is constructed with dummy. This copies the entire string's contents into an internal buffer, which is preallocated.dummy
is then cleared and then erased, freeing up its allocation.This means that in order to preallocate a
stringstream
, two allocations, one fill, and one copy takes place. The worst part is that during the expression, twice as much memory is needed for the desired allocation. Yikes!For most use cases, this might not matter at all and it's OK to take the extra fill and copy hit to have fewer reallocations.
虽然“搞乱 stringstream 的 rdbuf...可能很容易错了”,我继续拼凑出一个概念验证,无论如何都是为了好玩,因为它已经总是困扰我的是,没有简单的方法来为
stringstream
保留存储空间。同样,正如 @luke 所说,您可能最好优化分析器告诉您需要优化的内容,因此这只是为了解决“如果我无论如何都想这样做怎么办?”。我没有乱搞 stringstream 的 rdbuf,而是制作了自己的 rdbuf,效果非常好几乎是同样的事情。它仅实现了最小值,并使用
字符串
作为缓冲区。不要问我为什么将其称为VECTOR_output_stream
。这只是一个快速拼凑在一起的事情。Although "mucking around with the stringstream's rdbuf...is probably Very Easy To Get Wrong", I went ahead and hacked together a proof-of-concept anyway for fun, as it has always bugged me that there is no easy way to
reserve
storage forstringstream
. Again, as @luke said, you are probably better off optimizing what your profiler tells you needs optimizing, so this is just to address "What if I want to do it anyway?".Instead of mucking around with stringstream's rdbuf, I made my own, which does pretty much the same thing. It implements only the minimum, and uses a
string
as a buffer. Don't ask me why I called it aVECTOR_output_stream
. This is just a quickly-hacked-together thing.我不确定,但我怀疑
stringstream
的stringbuf
与结果string
紧密相关。所以我怀疑你可以使用 ss.seekp(reserved-1); ss.put('\0'); 保留ss
的底层string
内的reserved
字节数。实际上我想看到类似 ss.seekp(reserved); 的东西ss.trunc();,但是流没有trunc()
方法。I'm not sure, but I suspect that
stringbuf
ofstringstream
is tightly related with resultedstring
. So I suspect that you can usess.seekp(reserved-1); ss.put('\0');
to reservereserved
amount of bytes inside of underlyingstring
ofss
. Actually I'd like to see something likess.seekp(reserved); ss.trunc();
, but there is notrunc()
method for streams.