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

时间:2009-12-21 16:23:53

标签: c++ stl stringstream

我在我的应用程序中广泛使用std::stringstream来构造字符串和错误消息。 stringstreams通常是非常短的生命自动变量。

这样的使用会导致每个变量的堆重新分配吗?我应该从临时变为班级成员stringstream变量吗?

在后一种情况下,如何保留stringstream缓冲区? (我应该用足够大的字符串初始化它还是有更优雅的方法?)

4 个答案:

答案 0 :(得分:11)

您是否描述过您的执行情况,并发现它们是减速的来源?

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

至于预留空间......

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

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

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

您可以在此gamedev thread中找到更多想法。

修改

使用stringstream's rdbuf搞砸也可能是一种解决方案。这种方法可能很容易弄错,所以请be sure it's absolutely necessary。绝对不优雅或简洁。

答案 1 :(得分:2)

我不确定,但我怀疑stringbuf的{​​{1}}与结果stringstream紧密相关。因此,我怀疑您可以使用stringss.seekp(reserved-1); ss.put('\0');的基础reserved内保留string个字节数。实际上我希望看​​到像ss这样的内容,但是没有适用于流的ss.seekp(reserved); ss.trunc();方法。

答案 2 :(得分:0)

坏人

这是一个古老的问题,但是就Visual Studio 2019中的C ++ 1z / C ++ 2a而言,stringstream也不是保留缓冲区的理想方法。

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

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

  • seekp上的
  • stringstream似乎仍然是未定义的行为,并且/或者什么也不做。

善良

此代码段可以按预期工作,并且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然后被清除然后擦除,以释放其分配。

这意味着要预分配stringstream,需要进行两次分配,一次填充和一份副本。最糟糕的部分是在表达式期间,所需分配需要两倍的内存。 kes!

对于大多数用例,这可能根本没有关系,可以采取额外的填充和复制命中来减少重新分配。

答案 3 :(得分:0)

尽管“搞混stringstream's rdbuf ...很可能很容易出错”,但我还是继续hacked together a proof-of-concept取乐,因为它总是让我感到困惑,认为这并不容易reserve的{​​{1}}存储方式。再次,正如@luke所说,您可能最好对分析器告诉您的需求进行优化,因此,这只是解决“如果我仍然要这样做怎么办?”。

我自己做了自己的事情,而不是与stringstream's rdbuf混为一谈,这几乎是同一件事。它仅实现最小值,并使用stringstream作为缓冲区。不要问我为什么我称它为string。这只是一起快速被黑客入侵的事情。

VECTOR_output_stream