我应该预分配 std::stringstream 吗?

发布于 2024-08-15 18:34:48 字数 222 浏览 8 评论 0原文

我广泛使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

初见你 2024-08-22 18:34:48

您是否对您的执行情况进行了分析,并发现它们是导致速度缓慢的原因?

考虑它们的用法。它们主要是针对代码正常流程之外的错误消息吗?

至于保留空间......

某些实现可能会在为字符串流进行任何分配之前保留一个小缓冲区。 std::string 的许多实现都是这样做的。

另一种选择可能是(未经测试!)

std::string str;
str.reserve(50);
std::stringstream sstr(str);

您可能会在此 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!)

std::string str;
str.reserve(50);
std::stringstream sstr(str);

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.

黒涩兲箜 2024-08-22 18:34:48

缺点

这是一个老问题,但即使从 Visual Studio 2019 中的 C++1z/C++2a 开始,stringstream 也没有保留缓冲区的理想方法。

这个问题的其他答案根本不起作用,原因如下:

  • 在空字符串上调用reserve会产生一个空字符串,因此stringstream构造函数不需要分配来复制该字符串的内容。

  • stringstream 上的

    seekp 似乎仍然是未定义的行为和/或不执行任何操作。

好的

此代码段按预期工作,ss 已按照请求的大小进行了预分配。

std::string dummy(reserve, '\0');
std::stringstream ss(dummy);
dummy.clear();
dummy.shrink_to_fit();

该代码也可以写成一行 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 a stringstream 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.

std::string dummy(reserve, '\0');
std::stringstream ss(dummy);
dummy.clear();
dummy.shrink_to_fit();

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.

如梦初醒的夏天 2024-08-22 18:34:48

虽然“搞乱 stringstream 的 rdbuf...可能很容易错了”,我继续拼凑出一个概念验证,无论如何都是为了好玩,因为它已经总是困扰我的是,没有简单的方法来为 stringstream 保留存储空间。同样,正如 @luke 所说,您可能最好优化分析器告诉您需要优化的内容,因此这只是为了解决“如果我无论如何都想这样做怎么办?”。

我没有乱搞 stringstream 的 rdbuf,而是制作了自己的 rdbuf,效果非常好几乎是同样的事情。它仅实现了最小值,并使用字符串作为缓冲区。不要问我为什么将其称为 VECTOR_output_stream。这只是一个快速拼凑在一起的事情。

constexpr auto preallocated_size = 256;
auto stream = vector_output_stream(preallocated_size);
stream << "My parrot ate " << 3 << " cookies.";
cout << stream.str() << endl;

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 for stringstream. 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 a VECTOR_output_stream. This is just a quickly-hacked-together thing.

constexpr auto preallocated_size = 256;
auto stream = vector_output_stream(preallocated_size);
stream << "My parrot ate " << 3 << " cookies.";
cout << stream.str() << endl;
固执像三岁 2024-08-22 18:34:48

我不确定,但我怀疑 stringstreamstringbuf 与结果 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 of stringstream is tightly related with resulted string. So I suspect that you can use ss.seekp(reserved-1); ss.put('\0'); to reserve reserved amount of bytes inside of underlying string of ss. Actually I'd like to see something like ss.seekp(reserved); ss.trunc();, but there is no trunc() method for streams.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文