我在我的应用程序中广泛使用std::stringstream
来构造字符串和错误消息。 stringstreams
通常是非常短的生命自动变量。
这样的使用会导致每个变量的堆重新分配吗?我应该从临时变为班级成员stringstream
变量吗?
在后一种情况下,如何保留stringstream
缓冲区? (我应该用足够大的字符串初始化它还是有更优雅的方法?)
答案 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
紧密相关。因此,我怀疑您可以使用string
在ss.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