The first string argument for the string stream is stored as a pointer / garbage

Possible duplicate:
Printing a string into a temporary stream object in C ++
std :: ostringstream prints c-string address instead of its contents

I am trying to create a string using stringstream, just as you would use cout. This is for a bit of a logging class. The problem I am facing is that if the first argument in <operator is a string, when I subsequently print this stringstream with a call to stringstream :: str (), I get the garbage address, not the string. This only happens on the FIRST line. The following lines are beautiful. The rooms are always beautiful. Here is the code:

// class I use to print out the stream class StreamWriter { public: StreamWriter() {} ~StreamWriter() { std::string myMessage = m_stringstream.str(); std::cout << myMessage << std::endl; } std::stringstream m_stringstream; }; // macro for simplification #define OSRDEBUG (StreamWriter().m_stringstream) // actual use OSRDEBUG << "Hello " << "my " << "name is Pris " << 123456; // output 0x8054480my name is Pris 123456 0x8054480my name is Pris 123456 0x8054480my name is Pris 123456 0x8054480my name is Pris 123456 

Can anyone shed light on what is happening and how can I get around this problem?

EDIT: The following changes (in addition to padiablo examples) also work, supporting the use of a class destructor with a macro.

  // class I use to print out the stream class StreamWriter { public: StreamWriter() { m_stringstream = new std::stringstream; } ~StreamWriter() { std::string myMessage = m_stringstream.str(); std::cout << myMessage << std::endl; delete m_stringstream; } std::stringstream * m_stringstream; }; // macro for simplication #define OSRDEBUG *(StreamWriter().m_stringstream) 

The original question still stands because it looks like it should work ... and I think it is probably important to know when the time comes to put this in the product quality code.

+4
source share
4 answers

The problem is that the flow is temporary.

Prior to C ++ 11, there was no overload of operator<< , not related to the member, which accepted the rvalue reference as the first parameter (for example, allowing to record temporary streams).

Thus, the only valid operator<< overloads were members, since all non-member overloads accept a non- const reference and, as such, will not bind to temporary ones. One of these non-member overloads is one of them responsible for printing C lines (aka char const* ). Here one of the elements overloads:

 basic_ostream<Ch, Traits>& operator<<(void* p); 

And guess what the string literal is converting to. :)

After the first line, you will get a normal link from the call to operator<< , which then allows you to transfer non-member overloads.

+5
source

I honestly do not understand what is happening (this is due to the fact that your StreamWriter instance is temporary), but I see the same effect as paxdiablo, described both in GCC and in MSVC.

However, there is something that can solve the problem. Add the following helper to the StreamWriter class:

  ostream& get_ostream() { return m_stringstream; } 

and change the macro to:

 #define OSRDEBUG (StreamWriter().get_ostream()) 
+2
source

This, apparently, is a consequence of how you create the object. I am still studying (and you can get a better answer at the same time), but explicit object creation works fine:

 #include <iostream> #include <sstream> class StreamWriter { public: StreamWriter() {} ~StreamWriter() { std::cout << m_stringstream.str() << std::endl; } std::stringstream m_stringstream; }; int main (void) { StreamWriter *sw = new StreamWriter(); sw->m_stringstream << "Hello " << "my " << "name is Pris "; delete sw; return 0; } 

As for the instance on the stack:

 int main (void) { StreamWriter sw; sw.m_stringstream << "Hello " << "my " << "name is Pris "; return 0; } 

Both of them print out what you expect, but the following simplification of your code:

 int main (void) { StreamWriter().m_stringstream << "Hello " << "my " << "name is Pris "; return 0; } 

If you have just decided a solution, you can probably:

 #define ORSDEBUG StreamWriter sw; sw.m_stringstream 

and ensuring that you protect this area so that it does not try to create more than one sw , and that it is destroyed at the right time, as well as your initial attempt:

 { ORSDEBUG << "Hello " << "my " << "name is Pris"; } 
+1
source

I tried a couple of alternatives, and the only thing I got was something like this:

 #define OSRDEBUG(s) \ do \ { \ StreamWriter writer; \ writer.m_stringstream << s; \ } while (0) OSRDEBUG("Hello " << "my " << "name is Pris " << 123456); 

I personally used the above design for my own registration decisions, and saw how others do it.

I am not good enough to understand why your example does not work, but I think this is because temporary users do not stay alive long enough.

+1
source

Source: https://habr.com/ru/post/1400526/


All Articles