Tell me, please exist if std :: StringStream
Analog SHRINK_TO_FIT
?
For example, I use the flow of the specified type for serialization and deserialization of data. As you work, the stream line is constantly expanding and never narrows. Of course, you can do from time to time to do Seal with hands, but it will have negative effects on performance, considering the fact that the string capacity horrible flow will be small again, and Adding data to such a stream will again occur.
Minimally reproducible example:
# include & lt; sstream & gt;
INT MAIN ()
{
STD :: STRINGSTREAM SS;
For (Size_t i = 0; I & LT; 1'000'000'000; ++ I)
{
SS.PUT (I);
SS.GET ();
}
Return 0;
}
When starting on Windows
in the VS 2017
environment, the memory consumption is only grows (both in debug and release versions).
Answer 1, Authority 100%
In theory, this behavior is due to the implementation: STD :: StringStream
stores the entire thrown line regardless of what was read from it. API has no control over it.
The simplest will simply create a new STD :: StringStream and throw everything that is not read.
std :: stringstream SS;
// ...
SS & LT; & LT; "FOO BAR";
SS & GT; & GT; foo;
// ...
STD :: STRINGSTREAM NEWSS {};
NEWSS & LT; & LT; ss.rdbuf ();
SS = STD :: MOVE (NEWSS);
You can do this a little more efficiently by requesting the desired number of memory:
std :: string newbuf;
newbuf.reserve (ss.rdbuf () - & gt; in_avail ()); // can Allocate and more
STD :: STRINGSTREAM NEWSS {STD :: MOVE (NEWBUF)};
NEWSS & LT; & LT; ss.rdbuf ();
SS = STD :: MOVE (NEWSS);
// Note: SS.STR (). Capacity () will output a different size value
// T.K. StringStream :: Str () Returns a copy of the line
I can not say that this is guaranteed to offer memory, but apparently it works.
Alternatively, instead of using Std :: StringStream
You can implement your ring buffer for STD :: IOSTREAM
, but this is another story.
Answer 2, Authority 33%
Reading data from the flow STD :: StringStream
does not reduce the size of the internal flow buffer. It simply moves the read position indicator forward. Let’s rewrite your test example as follows:
# include & lt; iostream & gt;
#Include & lt; String & GT;
#Include & lt; sstream & gt;
Using std :: cout;
Using STD :: ENDL;
INT MAIN () {
STD :: STRINGSTREAM SS;
For (char i = '0'; i & lt; '3'; ++ i) {
//ss.str ("");
SS.PUT (I);
COUT & LT; & LT; "TELLP:" & lt; & lt; static_cast & lt; std :: streamoff & gt; (ss.tellp ()) & lt; & lt; Endl;
SS.GET ();
COUT & LT; & LT; "TELLG:" & lt; & lt; static_cast & lt; std :: streamoff & gt; (ss.tellg ()) & lt; & lt; Endl;
COUT & LT; & LT; ss.str () & lt; & lt; Endl & lt; & lt; Endl;
}
}
pin :
Tellp: 1
TELLG: 1.
0.
Tellp: 2.
TELLG: 2.
01.
TELLP: 3.
TELLG: 3.
012.
Uponcing the program, it is clear that as you write and read data to / from the stream, the corresponding position indicators are moved. But after reading from the stream, the size of the buffer does not decrease. All read characters remain in the inner buffer.
To prevent unlimited internal buffer growth, it is necessary either before recording / reading data to move the position / reading position indicators using the SEEKP ()
and seekg ()
to the beginning of the buffer. It will not affect the buffer size, and the old content does not clean. Just write to the thread will overwrite characters available in the inner buffer.
either completely replace the internal buffer on the empty string using the str ()
.
If in the given example, to rail // ss.str (") string);
, then output will be like :
Tellp: 1
TELLG: 1.
0.
Tellp: 1.
TELLG: 1.
1
Tellp: 1.
TELLG: 1.
2.