I'm currently in the memory-leak detection stage of debugging, and am running valgrind --leak-check=full --show-leak-kinds=all on my executable. However, I'm getting some confusing output in a loss record:
==26628== 2 bytes in 1 blocks are indirectly lost in loss record 2 of 343
==26628== at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26628== by 0x436EF6: void std::vector<unsigned char, std::allocator<unsigned char> >::_M_range_insert<char*>(__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsig$
==26628== by 0x4368EF: giga::Page::aux_load() (stl_vector.h:1291)
==26628== by 0x43499D: cachepp::SerialCache<cachepp::SimpleSerialCacheData, giga::Page>::allocate(std::shared_ptr<giga::Page> const&) (lineinterface.template:34)
...
The problem is in the trace for giga::Page::aux_load -- this function is defined by me, and most definitely not in the standard lib. I'm not sure why the line was not reported on this output line from the appropriate calling file.
I wasn't sure if code was necessary for this, but in case I do --
void giga::Page::aux_load() {
this->data.clear();
// deallocate the data vector
std::vector<uint8_t>().swap(this->data);
if(!this->get_is_dirty()) {
// load data into the page
FILE *fp = fopen(this->get_filename().c_str(), "r");
if(fseek(fp, this->file_offset, SEEK_SET) == -1) {
throw(exceptionpp::RuntimeError("giga::Page::aux_load", "invalid result returned from fseek"));
}
char *data = (char *) calloc(this->get_size(), sizeof(char));
if(fread((void *) data, sizeof(char), this->get_size(), fp) < this->get_size()) {
throw(exceptionpp::RuntimeError("giga::Page::aux_load", "invalid result returned from fread"));
}
fclose(fp);
this->data.insert(this->data.end(), data, data + this->get_size());
free((void *) data);
}
}
Any help would be greatly appreciated!
This is likely to be caused by valgrind stacktrace not showing inlined function call
defined at stl_vector.h:1291 and called somewhere inside aux_load.
The next version of Valgrind has support for showing inlined function,
using the option --read-inline-info=yes.
So, get and compile the latest valgrind svn version
See http://www.valgrind.org/downloads/repository.html
for instruction about how to get, configure and compile the valgrind svn version
This may not be the reason for the leaks in your report, but your code definitely will leak memory, without a doubt. It will leak if you throw an exception:
throw(exceptionpp::RuntimeError("giga::Page::aux_load", "invalid result returned from fread"));
The reason why it is a leak is that you previously called calloc, and the line where you free the data is never reached. You also have a dangling open file pointer if any exception is thrown by your function.
The answer to correct this is short and sweet:
Use std::ifstream, not FILE*. This will guarantee that your file is closed on function return, regardless of the reason for the return.
Use std::vector<char> dataV(get_size()), not calloc. This will guarantee that the memory is deallocated on function return, regardless of the reason for the return (in this case, use &dataV[0] or if using C++11 dataV.data() to get a pointer to the char buffer).
The topic you should read about is RAII: What is meant by Resource Acquisition is Initialization (RAII)?
Rewrite your code using these constructs above, and you will relieve yourself of the leaks in the function you posted.
The other changes you should use:
Check for get_size() == 0. If it's 0, then you can return immediately without having to open files.
There is no need for you to use this-> everywhere. It clutters the code and makes it harder to debug if there is an issue.
Related
I've tried several things already,
std::stringstream m;
m.empty();
m.clear();
both of which don't work.
For all the standard library types the member function empty() is a query, not a command, i.e. it means "are you empty?" not "please throw away your contents".
The clear() member function is inherited from ios and is used to clear the error state of the stream, e.g. if a file stream has the error state set to eofbit (end-of-file), then calling clear() will set the error state back to goodbit (no error).
For clearing the contents of a stringstream, using:
m.str("");
is correct, although using:
m.str(std::string());
is technically more efficient, because you avoid invoking the std::string constructor that takes const char*. But any compiler these days should be able to generate the same code in both cases - so I would just go with whatever is more readable.
You can clear the error state and empty the stringstream all in one line
std::stringstream().swap(m); // swap m with a default constructed stringstream
This effectively resets m to a default constructed state, meaning that it actually deletes the buffers allocated by the string stream and resets the error state. Here's an experimental proof:
int main ()
{
std::string payload(16, 'x');
std::stringstream *ss = new std::stringstream; // Create a memory leak
(*ss) << payload; // Leak more memory
// Now choose a way to "clear" a string stream
//std::stringstream().swap(*ss); // Method 1
//ss->str(std::string()); // Method 2
std::cout << "end" << std::endl;
}
Demo
When the demo is compiled with address sanitizer, memory usage is revealed:
=================================================================
==10415==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 392 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x514e80 in main (/tmp/1637178326.0089633/a.out+0x514e80)
#2 0x7f3079ffb82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
Indirect leak of 513 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x7f307b03a25c in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned long) (/usr/local/lib64/libstdc++.so.6+0x13725c)
#2 0x603000000010 (<unknown module>)
SUMMARY: AddressSanitizer: 905 byte(s) leaked in 2 allocation(s).
Pretty steep if you ask me. To hold just 16bytes of payload, we spent 905 bytes ... string streams are no toy. Memory is allocated in two parts:
The constructed string stream (392 bytes)
The extra buffer needed for the payload (513 bytes). The extraneous size has to do with the allocation strategy chosen by the stream and for payloads <= 8 bytes, blocks inside the initial object can be used.
If you enable method 1 (the one shown in this answer) the extra 513 (payload) bytes are reclaimed, because the stream is actually cleared.
If you enable method2 as suggested in the comments or other answers, you can see that all 905 bytes are in use by the time we exit.
In terms of program semantics, one may only care that the stream "appears" and "behaves" as empty, similar to how a vector::clear may leave the capacity untouched but render the vector empty to the user (of course vector would spend just 16 bytes here). Given the memory allocation that string stream requires, I can imagine this approach being often faster. This answer's primary goal is to actually clear the string stream, given that memory consumption that comes with it is no joke. Depending on your use case (number of streams, data they hold, frequency of clearing) you may choose the best approach.
Finally note that it's rarely useful to clear the stream without clearing the error state and all inherited state. The one liner in this answer does both.
This should be the most reliable way regardless of the compiler:
m=std::stringstream();
m.str("");
seems to work.
I am always scoping it:
{
std::stringstream ss;
ss << "what";
}
{
std::stringstream ss;
ss << "the";
}
{
std::stringstream ss;
ss << "heck";
}
my 2 cents:
this seemed to work for me in xcode and dev-c++, I had a program in the form of a menu that if executed iteratively as per the request of a user will fill up a stringstream variable which would work ok the first time the code would run but would not clear the stringstream the next time the user will run the same code. but the two lines of code below finally cleared up the stringstream variable everytime before filling up the string variable. (2 hours of trial and error and google searches), btw, using each line on their own would not do the trick.
//clear the stringstream variable
sstm.str("");
sstm.clear();
//fill up the streamstream variable
sstm << "crap" << "morecrap";
There are many other answers that "work", but they often do unnecessary copies or reallocate memory.
Swapping streams means that you need to discard one of them, wasting the memory allocation. Same goes for assigning a default-constructed stream,
Assigning to the string in the string buffer (via stringstream::str or stringbuf::str) may lose the buffer already allocated by the string.
The canonical way to clear the string stream would be:
void clear(std::stringstream &stream)
{
if (stream.rdbuf()) stream.rdbuf()->pubseekpos(0);
}
The canonical way to get the size of the data in the stream's buffer is:
std::size_t availSize() (const std::stringstream& stream)
{
if (stream.rdbuf())
return std::size_t(
stream.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out));
else
return 0;
}
The canonical way to copy the data from the stream to some other preallocated buffer and then clear it would then be:
std::size_t readAndClear(std::stringstream &stream, void* outBuf, std::size_t outSize)
{
auto const copySize = std::min(availSize(stream), outSize);
if (!copySize) return 0; // takes care of null stream.rdbuf()
stream.rdbuf()->sgetn(outBuf, copySize);
stream.rdbuf()->pubseekpos(0); // clear the buffer
return copySize;
}
I intend this to be a canonical answer. Language lawyers, feel free to pitch in.
It's a conceptual problem.
Stringstream is a stream, so its iterators are forward, cannot return. In an output stringstream, you need a flush() to reinitialize it, as in any other output stream.
These do not discard the data in the stringstream in gnu c++
m.str("");
m.str() = "";
m.str(std::string());
The following does empty the stringstream for me:
m.str().clear();
I've tried several things already,
std::stringstream m;
m.empty();
m.clear();
both of which don't work.
For all the standard library types the member function empty() is a query, not a command, i.e. it means "are you empty?" not "please throw away your contents".
The clear() member function is inherited from ios and is used to clear the error state of the stream, e.g. if a file stream has the error state set to eofbit (end-of-file), then calling clear() will set the error state back to goodbit (no error).
For clearing the contents of a stringstream, using:
m.str("");
is correct, although using:
m.str(std::string());
is technically more efficient, because you avoid invoking the std::string constructor that takes const char*. But any compiler these days should be able to generate the same code in both cases - so I would just go with whatever is more readable.
You can clear the error state and empty the stringstream all in one line
std::stringstream().swap(m); // swap m with a default constructed stringstream
This effectively resets m to a default constructed state, meaning that it actually deletes the buffers allocated by the string stream and resets the error state. Here's an experimental proof:
int main ()
{
std::string payload(16, 'x');
std::stringstream *ss = new std::stringstream; // Create a memory leak
(*ss) << payload; // Leak more memory
// Now choose a way to "clear" a string stream
//std::stringstream().swap(*ss); // Method 1
//ss->str(std::string()); // Method 2
std::cout << "end" << std::endl;
}
Demo
When the demo is compiled with address sanitizer, memory usage is revealed:
=================================================================
==10415==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 392 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x514e80 in main (/tmp/1637178326.0089633/a.out+0x514e80)
#2 0x7f3079ffb82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
Indirect leak of 513 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x7f307b03a25c in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned long) (/usr/local/lib64/libstdc++.so.6+0x13725c)
#2 0x603000000010 (<unknown module>)
SUMMARY: AddressSanitizer: 905 byte(s) leaked in 2 allocation(s).
Pretty steep if you ask me. To hold just 16bytes of payload, we spent 905 bytes ... string streams are no toy. Memory is allocated in two parts:
The constructed string stream (392 bytes)
The extra buffer needed for the payload (513 bytes). The extraneous size has to do with the allocation strategy chosen by the stream and for payloads <= 8 bytes, blocks inside the initial object can be used.
If you enable method 1 (the one shown in this answer) the extra 513 (payload) bytes are reclaimed, because the stream is actually cleared.
If you enable method2 as suggested in the comments or other answers, you can see that all 905 bytes are in use by the time we exit.
In terms of program semantics, one may only care that the stream "appears" and "behaves" as empty, similar to how a vector::clear may leave the capacity untouched but render the vector empty to the user (of course vector would spend just 16 bytes here). Given the memory allocation that string stream requires, I can imagine this approach being often faster. This answer's primary goal is to actually clear the string stream, given that memory consumption that comes with it is no joke. Depending on your use case (number of streams, data they hold, frequency of clearing) you may choose the best approach.
Finally note that it's rarely useful to clear the stream without clearing the error state and all inherited state. The one liner in this answer does both.
This should be the most reliable way regardless of the compiler:
m=std::stringstream();
m.str("");
seems to work.
I am always scoping it:
{
std::stringstream ss;
ss << "what";
}
{
std::stringstream ss;
ss << "the";
}
{
std::stringstream ss;
ss << "heck";
}
my 2 cents:
this seemed to work for me in xcode and dev-c++, I had a program in the form of a menu that if executed iteratively as per the request of a user will fill up a stringstream variable which would work ok the first time the code would run but would not clear the stringstream the next time the user will run the same code. but the two lines of code below finally cleared up the stringstream variable everytime before filling up the string variable. (2 hours of trial and error and google searches), btw, using each line on their own would not do the trick.
//clear the stringstream variable
sstm.str("");
sstm.clear();
//fill up the streamstream variable
sstm << "crap" << "morecrap";
There are many other answers that "work", but they often do unnecessary copies or reallocate memory.
Swapping streams means that you need to discard one of them, wasting the memory allocation. Same goes for assigning a default-constructed stream,
Assigning to the string in the string buffer (via stringstream::str or stringbuf::str) may lose the buffer already allocated by the string.
The canonical way to clear the string stream would be:
void clear(std::stringstream &stream)
{
if (stream.rdbuf()) stream.rdbuf()->pubseekpos(0);
}
The canonical way to get the size of the data in the stream's buffer is:
std::size_t availSize() (const std::stringstream& stream)
{
if (stream.rdbuf())
return std::size_t(
stream.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out));
else
return 0;
}
The canonical way to copy the data from the stream to some other preallocated buffer and then clear it would then be:
std::size_t readAndClear(std::stringstream &stream, void* outBuf, std::size_t outSize)
{
auto const copySize = std::min(availSize(stream), outSize);
if (!copySize) return 0; // takes care of null stream.rdbuf()
stream.rdbuf()->sgetn(outBuf, copySize);
stream.rdbuf()->pubseekpos(0); // clear the buffer
return copySize;
}
I intend this to be a canonical answer. Language lawyers, feel free to pitch in.
It's a conceptual problem.
Stringstream is a stream, so its iterators are forward, cannot return. In an output stringstream, you need a flush() to reinitialize it, as in any other output stream.
These do not discard the data in the stringstream in gnu c++
m.str("");
m.str() = "";
m.str(std::string());
The following does empty the stringstream for me:
m.str().clear();
This is probably a noob question. I am using Marmalade SDK. If I allocate some memory for a char array dynamically I get an access violation. I cannot figure out what I am doing wrong.
Is this a valid way to use malloc and free?
const char* CClass::caption(int something)
{
...
//char stringPrediction[2000]; // <--- This works
size_t string01_Size = strlen(string01);
size_t string02_Size = strlen(string02);
...
stringX = (char *)malloc(string01_Size + string02_Size + 1); // <- Access violation
strcpy(stringX , string01);
strcat(stringX , " ");
strcat(stringX , string02);
return stringX ;
}
Destructor:
CClass::~CClass(void)
{
free(stringX);
}
Then I use it to set the caption of a label on a Button click event
... OnClick...(...)
{
CClass someObject;
label.setCaption(someObject.caption());
}
After a few clicks I get access violation.
Unhandled exception at 0x1007ECB8 (s3e_simulator_debug.dll) in
s3e_simulator_debug.exe: 0xC0000005: Access violation writing
location 0x0000000C.
EDIT: It seems the problems is:
stringX = (char *)malloc(string01_Size + string02_Size + 1);
I have failed to allocate space for this:
strcat(stringX , " ");
This should be better:
stringX = (char *)malloc(string01_Size + 1 + string02_Size + 1);
1.
You're not testing for the case that malloc fails. The error suggests you're trying to dereference a null pointer - the pointer returned when malloc fails.
2.
It doesn't look like you're accounting for the null-byte terminator when calculating the size of your buffer. Assuming string01_Size and string02_Size are the number of characters not including the null byte, you're overflowing your buffer.
Both actions result in undefined behaviour.
Access violation encountered during call of malloc or free in most cases indicates that the heap is corrupt. Due to, most commonly overrun or double free or free issued on dangling pointer, happened sometime earlier. May be way earlier.
From the posted code it's not possible to deduce, as it effectively starts with the crash.
To deal with it you may try valgrind, app verifier, other runtime tools helping with corruption. For that one particular issue -- for the general you should not be there in the first place, using malloc, the str* function an all the inherited crap from C.
Consistent use of collection classes, String class, etc would prevent too many cases leading to drastic problems.
You've basically spotted the issue: by not allocating for the space you're second strcat will overrun and probably crunch the heap pointers of the next block. Additional things to watch (you're probably be doing this anyway) are to free stringX in CClass::caption() before reallocating so you don't leak. Whatever you really should check that the malloc has not failed before use.
As others have suggested, it may be better to use std::string. You can always convert these to char* if required. Of course, if you do so you should consider that exceptions might be thrown and program accordingly.
I'm profiling code of a game I wrote and I'm wondering how it is possible that the following snippet causes an heap increase of 4kb (I'm profiling with Heapshot Analysis of Xcode) every time it is executed:
u8 WorldManager::versionOfMap(FILE *file)
{
char magic[4];
u8 version;
fread(magic, 4, 1, file); <-- this is the line
fread(&version,1,1,file);
fseek(file, 0, SEEK_SET);
return version;
}
According to the profiler the highlighted line allocates 4.00Kb of memory with a malloc every time the function is called, memory which is never released. This thing seems to happen with other calls to fread around the code, but this was the most eclatant one.
Is there anything trivial I'm missing? Is it something internal I shouldn't care about?
Just as a note: I'm profiling it on an iPhone and it's compiled as release (-O2).
If what you're describing is really happening and your code has no bugs elsewhere, it is a bug in the implementation, I think.
More likely I think, is the possibility that you don't close the file. Stdio streams use buffering by default if the device is non-interactive, and the buffer is allocated either at the time the file is opened or when I/O is performed. While only one buffer should be allocated, you can certainly leak the buffer by forgetting to close the file. But certainly, closing the file should free the buffer. Don't forget to check the value returned by fclose.
Supposing for the sake of argument that you are correctly closing the file there are a couple of other nits in your code which won't be causing this problem but I'll mention anyway.
First your fread call reads an object having one member of size 4. You actually have an object having 4 members of size 1. In other words the numeric arguments to fread are swapped. This makes a difference only in the meaning of the return value (important in the case of a partial read).
Second, while your first call to fread correctly hard-codes the size of char as 1 (in C, that is the definition of 'size'), it's probably better stylistically to use sizeof(u8) in the second call to fread.
If the idea that this really is a memory leak is a correct interpretation (and there aren't any bugs elsewhere) then you may be able to work around the problem by turning off the stdio buffering for this particular file:
bool WorldManager::versionOfMap(FILE *file, bool *is_first_file_io, u8 *version)
{
char magic[4];
bool ok = false;
if (*is_first_file_io)
{
// we ignore failure of this call
setvbuf(file, NULL, _IONBF, 0);
*is_first_file_io = false;
}
if (sizeof(magic) == fread(magic, 1, sizeof(magic), file)
&& 1 == fread(version, sizeof(*version), 1, file))
{
ok = true;
}
if (-1 == fseek(file, 0L, SEEK_SET))
{
return false;
}
else
{
return ok && 0 == memcmp(magic, EXPECTED_MAGIC, sizeof(magic));
}
}
Even if we're going with the hypothesis that this really is a bug, and the leak is real, it is well worth condensing your code to the smallest possible example that still demonstrates the problem. If doing that reveals the true bug, you win. Otherwise, you will need the minimal example to report the bug in the implementation.
I've tried several things already,
std::stringstream m;
m.empty();
m.clear();
both of which don't work.
For all the standard library types the member function empty() is a query, not a command, i.e. it means "are you empty?" not "please throw away your contents".
The clear() member function is inherited from ios and is used to clear the error state of the stream, e.g. if a file stream has the error state set to eofbit (end-of-file), then calling clear() will set the error state back to goodbit (no error).
For clearing the contents of a stringstream, using:
m.str("");
is correct, although using:
m.str(std::string());
is technically more efficient, because you avoid invoking the std::string constructor that takes const char*. But any compiler these days should be able to generate the same code in both cases - so I would just go with whatever is more readable.
You can clear the error state and empty the stringstream all in one line
std::stringstream().swap(m); // swap m with a default constructed stringstream
This effectively resets m to a default constructed state, meaning that it actually deletes the buffers allocated by the string stream and resets the error state. Here's an experimental proof:
int main ()
{
std::string payload(16, 'x');
std::stringstream *ss = new std::stringstream; // Create a memory leak
(*ss) << payload; // Leak more memory
// Now choose a way to "clear" a string stream
//std::stringstream().swap(*ss); // Method 1
//ss->str(std::string()); // Method 2
std::cout << "end" << std::endl;
}
Demo
When the demo is compiled with address sanitizer, memory usage is revealed:
=================================================================
==10415==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 392 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x514e80 in main (/tmp/1637178326.0089633/a.out+0x514e80)
#2 0x7f3079ffb82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
Indirect leak of 513 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x7f307b03a25c in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned long) (/usr/local/lib64/libstdc++.so.6+0x13725c)
#2 0x603000000010 (<unknown module>)
SUMMARY: AddressSanitizer: 905 byte(s) leaked in 2 allocation(s).
Pretty steep if you ask me. To hold just 16bytes of payload, we spent 905 bytes ... string streams are no toy. Memory is allocated in two parts:
The constructed string stream (392 bytes)
The extra buffer needed for the payload (513 bytes). The extraneous size has to do with the allocation strategy chosen by the stream and for payloads <= 8 bytes, blocks inside the initial object can be used.
If you enable method 1 (the one shown in this answer) the extra 513 (payload) bytes are reclaimed, because the stream is actually cleared.
If you enable method2 as suggested in the comments or other answers, you can see that all 905 bytes are in use by the time we exit.
In terms of program semantics, one may only care that the stream "appears" and "behaves" as empty, similar to how a vector::clear may leave the capacity untouched but render the vector empty to the user (of course vector would spend just 16 bytes here). Given the memory allocation that string stream requires, I can imagine this approach being often faster. This answer's primary goal is to actually clear the string stream, given that memory consumption that comes with it is no joke. Depending on your use case (number of streams, data they hold, frequency of clearing) you may choose the best approach.
Finally note that it's rarely useful to clear the stream without clearing the error state and all inherited state. The one liner in this answer does both.
This should be the most reliable way regardless of the compiler:
m=std::stringstream();
m.str("");
seems to work.
I am always scoping it:
{
std::stringstream ss;
ss << "what";
}
{
std::stringstream ss;
ss << "the";
}
{
std::stringstream ss;
ss << "heck";
}
my 2 cents:
this seemed to work for me in xcode and dev-c++, I had a program in the form of a menu that if executed iteratively as per the request of a user will fill up a stringstream variable which would work ok the first time the code would run but would not clear the stringstream the next time the user will run the same code. but the two lines of code below finally cleared up the stringstream variable everytime before filling up the string variable. (2 hours of trial and error and google searches), btw, using each line on their own would not do the trick.
//clear the stringstream variable
sstm.str("");
sstm.clear();
//fill up the streamstream variable
sstm << "crap" << "morecrap";
There are many other answers that "work", but they often do unnecessary copies or reallocate memory.
Swapping streams means that you need to discard one of them, wasting the memory allocation. Same goes for assigning a default-constructed stream,
Assigning to the string in the string buffer (via stringstream::str or stringbuf::str) may lose the buffer already allocated by the string.
The canonical way to clear the string stream would be:
void clear(std::stringstream &stream)
{
if (stream.rdbuf()) stream.rdbuf()->pubseekpos(0);
}
The canonical way to get the size of the data in the stream's buffer is:
std::size_t availSize() (const std::stringstream& stream)
{
if (stream.rdbuf())
return std::size_t(
stream.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out));
else
return 0;
}
The canonical way to copy the data from the stream to some other preallocated buffer and then clear it would then be:
std::size_t readAndClear(std::stringstream &stream, void* outBuf, std::size_t outSize)
{
auto const copySize = std::min(availSize(stream), outSize);
if (!copySize) return 0; // takes care of null stream.rdbuf()
stream.rdbuf()->sgetn(outBuf, copySize);
stream.rdbuf()->pubseekpos(0); // clear the buffer
return copySize;
}
I intend this to be a canonical answer. Language lawyers, feel free to pitch in.
It's a conceptual problem.
Stringstream is a stream, so its iterators are forward, cannot return. In an output stringstream, you need a flush() to reinitialize it, as in any other output stream.
These do not discard the data in the stringstream in gnu c++
m.str("");
m.str() = "";
m.str(std::string());
The following does empty the stringstream for me:
m.str().clear();