Printing a string into a temporary stream object in C ++

I have a special type of ostringstream that I am trying to output text as a temporary object, but I have problems. To be clear, this is essentially what I want to do:

ostringstream() << "PARTY DOWN!" << endl; 

Now, before you say: β€œBut Zach, this code is completely useless! The object is destroyed at the end of the line, how would you even know that he did something?”, Listen to me. I am not trying to do this with a simple ostringstream, but rather from a derived class in which the destructor actually provides a way to output data from the object. So it actually looks a lot bigger:

 specialstringstream() << "PARTY DOWN!" << endl; 

If specialstringstream has a destructor that unloads text elsewhere.

I will not go into details why I do it. You will have to trust me that this makes sense for what I need to do, and it fits perfectly into the existing gigantic code base.

Here's the problem: when I do this, everything compiles and starts, but I get the address of the pointer printed on my output, instead of "PARTY DOWN!". line. I decided that this was because the operator selected by the compiler to execute the stream was ostream& operator<< (const void* val) and not ostream& operator<< (ostream& out, const char* s ) .

I have a vague idea of ​​why, but I don’t understand how this works. What can I do to get char * s to print to a temporary stringstream instance?

Here is a short version of the SpecialStringStream object that demonstrates the behavior:

 class SpecialStringStream : public ostringstream { public: SpecialStringStream(ostream* regularStream) { regularStream_ = regularStream; } ~SpecialStringStream() { if (regularStream_ != NULL) (*regularStream_) << str(); } private: ostream* regularStream_; }; 

When I do something like: SpecialStringStream(someStreamPtr) << "PARTY DOWN!" << endl; SpecialStringStream(someStreamPtr) << "PARTY DOWN!" << endl; , I get the address of the pointer, such as "00444D60" in my message, and not in the message.

EDIT: Since I'm too new to answering my own question, this is what I decided thanks to all the answers.

I came up with the following solution that works under Visual C ++ 8 and all the other compilers I needed. I created a template statement that basically splits the const SpecialStringStream of its constant, discards it as ostream and allows the ostream operators to do their job. Feel free to tear it to shreds in the comments and warn me about all the terrible potential mistakes that I have presented!

 template <class T> std::ostream& operator<<(const SpecialStringStream &o, T msg) { return static_cast<std::ostream&>(const_cast<SpecialStringStream&>(o)) << msg; } 
+4
source share
4 answers

Overloading ostream& operator<< (ostream& out, const char*) not viable because your temporary connection will not be bound to the ostream& non-constant link. There is not much you can do about it (since you cannot use rvalue for an lvalue), except declaring a local variable and using this:

 { specialstringstream ss; ss << "Hello world" << std::endl; // OK, can bind to lvalue } 

Possible solution: you can declare another overload that accepts an rvalue reference:

 std::ostream & operator<<(specialstringstream && o, const char * s) { return o << s; // note: *not* "std::move(o)" } 
+4
source

You do not want to use stringstream. You want to implement basic_streambuf, which is written to your custom string.

the streams themselves are responsible for formatting and similar functions; streambufs are responsible for what ultimately becomes a data sink.

In the end, the entire string stream is iostream, with a basic_stringbuf binding.

+2
source

Maybe there is a better way, but I decided a different solution:

 #include <iostream> #include <sstream> class LogClass { template <typename T> friend const LogClass& operator << (const LogClass& lc, const T& v); public: LogClass() : str(new std::ostringstream()) , refCount(new int(1)) {} LogClass(const LogClass& other) : str(other.str) { ++(*refCount); } ~LogClass() { --(*refCount); if (!*refCount) { delete refCount; std::cout << str->str() << std::endl; delete str; } } private: mutable std::ostringstream *str; int *refCount; LogClass& operator = (const LogClass&); }; template <typename T> const LogClass& operator << (const LogClass& lc, const T& v) { (*lc.str) << v; return lc; } int main(int , char**) { for (size_t i = 0; i < 10 ; ++i) { LogClass() << "PARTY DOWN! " << i; } } 

Running with valgrind:

valgrind --tool = memcheck --leak-check = full./LogClass

== 16197 == Memcheck, memory error detector

== 16197 == Copyright (C) 2002-2010 and GNU GPL'd by Julian Seward et al.

== 16197 == Using Valgrind-3.7.0.SVN and LibVEX; repeat with -h for copyright information

== 16197 == Command: ./ LogClass

== 16197 ==

PARTY DOWN! 0

PARTY DOWN! 1

PARTY DOWN! 2

PARTY DOWN! 3

PARTY DOWN! 4

PARTY DOWN! 5

PARTY DOWN! 6

PARTY DOWN! 7

PARTY DOWN! eight

PARTY DOWN! nine

== 16197 ==

== 16197 == HEAP SUMMARY:

== 16197 == used on exit: 0 bytes in 0 blocks

== 16197 == total heap usage: 40 allocation, 40 frees, 7,350 bytes allocated

== 16197 ==

== 16197 == All heap blocks were freed - no leaks possible

== 16197 ==

== 16197 == To count detected and suppressed errors, try again: -v

== 16197 == ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 of 8)

This is what I wanted, but it is not thread safe . Use shared_ptr from boost to do so.

+2
source

here is the workaround i am using:

 #define STRM2STR(x) (dynamic_cast<std::ostringstream &>(std::ostringstream() << std::dec << x).str()) 

Inserting std :: dec will result in a call to ostream :: operator <<(ios_base & (* pf) (ios_base &)), which returns a useful stream <

0
source

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


All Articles