std::stringstream as parameter - c++

I'm somewhat new to the C++ language. I'm writing a utility class for logging to file. It works beautifully except that now I would like to enhance it by making it more convenient to use (e.g. pass stringstreams to a log function).
This is what I've been trying and it hasn't worked.
definition:
void LogStream( std::stringstream i_Log ){
m_FileHandle << i_Log << std::endl;
}
call:
m_LogObject->LogStream( "MKLBSearchEngine::Search( " << x << ", " << i_Filter << " ) - No Results Found" );

There are several problems with your solution. The first is that you're
passing stringstream by value, and it doesn't support copy. You need
by reference. The second is that at the call site, the return value of
the operator<< overloads is ostream&, not stringstream, and since
stringstream isn't a base class of ostream& (it's the other way
round), you can't initialize the stringstream (or the stringstream&)
with it. And finally, there's no operator<< which takes a
stringstream as the right hand parameter, so the statement in the
LogStream function can't work. Finally, this is going to be somewhat
awkward for the user anyway. A log of operator<< are non-members,
with an ostream& non-const reference as first argument, so you can't
call them with a temporary as the left argument. (In your example call,
of course, you forgot to create the std::ostringstream anyway; it
won't compiler because there is no overload of << which takes a char
const[] or a char const* as its left hand operand.)
There are work-arounds for almost all of these problems. Something
like:
void LogStream( std::ostream& text )
{
std::ostringstream& s = dynamic_cast<std::ostringstream&>(text);
m_FileHandle << s.str() << std::endl;
}
handles all of the problems except the last; the last has to be handled
by the client, something like:
m_LogObject->LogStream( std::ostringstream().flush() << "..." << x );
(The call to std::ostream::flush() returns a non-const reference to
the stream, which can be used to initialize further std::ostream&.
And while you can't initialize a non-const reference with a temporary,
you can call a non-const member function on it.)
The awkwardness of this for the client code makes me generally prefer a
more complex solution. I define a special LogStreamer class,
something like:
class LogStreamer
{
boost::shared_ptr< std::ostream > m_collector;
std::ostream* m_dest;
public:
LogStreamer( std::ostream& dest )
, m_collector( new std::ostringstream )
, m_dest( &dest )
{
}
~LogStreamer()
{
if ( m_collector.unique() ) {
*m_dest << m_collector->str() << std::endl;
}
}
template <typename T>
LogStreamer& operator<<( T const& value )
{
*m_collector << value;
return *this;
}
};
and
LogStreamer LogStream() { return LogStreamer( m_FileHandle ); }
The client code can then write:
m_LogObject->LogStream() << "..." << x;
In my own code: the log object is always a singleton, the call is
through a macro, which passes __FILE__ and __LINE__ to the LogStream()
function, and the final target ostream is a special streambuf with a
special function, called by LogStream(), which takes a filename and a
line number, outputs them, along with the time stamp, at the start of
the next line output, and indents all other lines. A filtering
streambuf with something like:
class LogFilter : public std::streambuf
{
std::streambuf* m_finalDest;
std::string m_currentHeader;
bool m_isAtStartOfLine;
protected:
virtual int overflow( int ch )
{
if ( m_isAtStartOfLine ) {
m_finalDest->sputn( m_currentHeader.data(), m_currentHeader.size() );
m_currentHeader = " ";
}
m_isAtStartOfLine = (ch == '\n');
return m_finalDest->sputc( ch );
}
virtual int sync()
{
return m_finalDest->sync();
}
public:
LogFilter( std::streambuf* dest )
: m_finalDest( dest )
, m_currentHeader( "" )
, m_isAtStartOfLine( true )
{
}
void startEntry( char const* filename, int lineNumber )
{
std::ostringstream header;
header << now() << ": " << filename << " (" << lineNumber << "): ";
m_currentHeader = header.str();
}
};
(The function now(), of course, returns a std::string with the
timestamp. Or a struct tm, and you've written a << for tm.)

You have a problem with your design. You don't want to accept a stream as a parameter, either accept a string, or make your class behave as a stream (or both).
If you make your object behave as a stream, then you do the following:
m_LogObject << "what to log" << etc;
To do that, simply override the << operator.

Your call should look like
m_LogObject->LogStream( stringstream() << "MKLBSearchEngine::Search( " << x
<< ", " << i_Filter << " ) - No Results Found" );
since you need to create your stringstream object that you will be passing to the function.
This call implies that you already have a desired output stream so i'd also recommend you changing your class design to use operator<< for logging unless it is already overloaded.

Your function call won't work, as "MKLBSearchEngine::Search( " is of type const char* and that has no overload for the << operator. It won't work with std::string("MKLBSearchEngine::Search( ") either, as also std::string doesn't have such an operator. What you can do is call it with std::stringstream("MKLBSearchEngine::Search( "), which converts the first argument to a stream, such that the following operators work on this stream. But as others pointed out, you will have to make the function argument a const reference, as streams are not copyable (even then it would be quite inefficient). Also just writing a std::stringstream into the file won't do what you want (if it works anyway), instead you have to take its contents (the underlying std::string). So all in all your code should look like:
void LogStream( const std::stringstream &i_Log ){ m_FileHandle << i_Log.str() << std::endl; }
...
m_LogObject->LogStream( std::stringstream("MKLBSearchEngine::Search( ") << x << ", " << i_Filter << " ) - No Results Found" );
But you could also just use a LogString(const std::string &) and let the user of this function call stream.str() himself.

You can't pass stream objects by value (since they are not copyable), so you need to pass by (and store) references:
void LogStream(std::stringstream& i_Log){
m_FileHandle << i_Log << std::endl;
}
This probably won't do what you're expecting though (it will probably print an address of i_Log, for rather obscure reasons).
If your intention is to take stuff OUT of the stringstream, this might do what you want:
i_Log.get( *m_FileHandle.rdbuf() );

You are passing std::stringstream instance by value. You want to avoid copying and pass it by reference (or pointer). For example:
void LogStream ( std::stringstream & i_Log ){ m_FileHandle << i_Log << std::endl; }
Read more about C++ references.

Related

Custom class ostringstream output error

I don't know why this is erroring, but I'm just trying to add something "akin" to endl so that I can throw what's in an ostringstream to our debugger. I have the following:
class debug_stream_info
{
public:
debug_stream_info(int errorLine, char *errorFile, int level)
:m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
{
}
friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
private:
int m_errorLine;
std::string m_errorFile;
int m_logLevel;
};
std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
// Write the stream's contents to cpu_debug
// Deleted custom logging function. No errors here though
// Clear the stream for re-use.
os.str("");
os.seekp(0);
return os;
}
int main(int argc, char** argv)
{
std::ostringstream myout;
myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers" << debug_stream_info(__LINE__, __FILE__, LOG_LEVEL);
return 0;
}
The error I'm getting is: error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'debug_stream_info' (or there is no acceptable conversion) for the line in main. This is on VS2008.
I'm including sstream, iostream, etc, and have the namespaces set up right. I'm getting no other errors. I even tried replacing all occurrances of basic_ostream with just ostringstream and there was no difference (I'll be having a w_char version later, but I wanted the simple case to work first). I made the object on the line above and then passed a fully-constructed object on the line, and the error was exactly the same. I've changed the signature of the second argument to and from const with no change as well.
Any ideas on what I'm doing wrong here?
Edit: since EVERY response seems to want to put it there, I can NOT use std::ostream because I want this to work ONLY for std::ostringstream (and std::basic_ostringstream) and not for any type of output stream. Besides, the function wouldn't compile with ostream anyways, since I'm using the os.str() method, which isn't in ostream, only the sub-classes.
The real problem with your code is that you've overloaded std::ostringstream rather than std::ostream. So your code would work if you write this:
debug_stream_info info(/** blah blah**/);
std::ostringstream oss;
oss << info ; //OK
However this will not work:
oss << 1 << info; //ERROR
This is compilation error because the expression oss<<1 returns an object of type std::ostream& which doesn't have overload which takes debug_stream_info as second argument. That means if you use cast as:
static_cast<std::ostringstream&>(oss << 1) << info; //OK
then that should work again.
So the solution is to overload std::ostream, instead of std::basic_ostringstream.
Also, the second parameter should be const & . This is also a problem with your code.
So write this:
std::ostream& operator<<(std::ostream&, debug_stream_info const &);
//^^^^^^^ note this
The second parameter should be const & so that you could write temporary objects to the stream.
debug_stream_info(__LINE__, __FILE__, LOG_LEVEL); is creating unnamed object which is not returning anything hence error
#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;
class debug_stream_info
{
public:
debug_stream_info(int errorLine, char *errorFile, int level)
:m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
{
}
friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
std::ostringstream& fun(std::ostringstream& os)
{
os<<"Ashish"<<endl;
return os;
}
private:
int m_errorLine;
std::string m_errorFile;
int m_logLevel;
};
std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
// Write the stream's contents to cpu_debug
// Deleted custom logging function. No errors here though
// Clear the stream for re-use.
// os.str("");
// os.seekp(0);
return os;
}
int main(int argc, char** argv)
{
std::ostringstream myout, test;
myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers"
<< debug_stream_info(1, "/home/ashish/test", 1).fun(test);
return 0;
}
Nawaz has explained very clearly why you're getting the error. The
usual solution in this case is to define your own stream type, unrelated
to std::istream. Something along the lines of:
class DebugStream
{
std::ostringstring* collector;
public:
template <typename T>
DebugStream& operator<<( T const& value )
{
if ( collector != NULL ) {
*collector << value;
}
return *this;
}
};
There are infinite variations on this; in your case, you could add a
non-template member function for your type; more likely, you'd add a
constructor which took the same arguments:
DebugStream( int lineNumber, std::string const& filename, int logLevel )
: collector( isActive( logLevel ) ? new std::ostringstream : NULL )
{
// Initial insertion of lineNumber, filename, timestamp...
}
You can also add a destructor which atomically flushes the collected
data to a file (or sends an email, or writes it to the system log, or
whatever). (Be very careful about this. You don't want an exception to
escape from the destructor, even if the logging fails.)
Finally, you might want to use a custom streambuf, rather than
stringstream. Say one that keeps the allocated buffer from one
instance to the next. And if you do this, rather than newing the
stream each time, you might pick up an instance from a table, indexed by
the log level (and initialized from a configuration file).

Trying to overload cout << operator but its not working

I snipped the irrelevant parts out of my class here. I don't know what I'm doing wrong, just trying to be able to cout << the object.
#include <iostream>
class Snipped
{
public:
friend std::ostream& operator<<(std::ostream& os, const Snipped& s);
protected:
private:
};
std::ostream& operator<<(std::ostream& os, const Snipped& s)
{
os << "test";
return os;
}
int main(int argc, char* argv[])
{
Snipped* s = new Snipped();
std::cout << s << std::endl << s;
delete s;
return 0;
}
Expected output:
test
test
Actual output:
0x12ae20
0x12ae20 (random memory location?)
std::cout << s << std::endl << s;
You are calling << with an address, you need to call it with object of type Snipped.
The line of code above won't call your overloaded operator function because the parameters of the overloaded function do not match.
You need to call:
std::cout << *s << std::endl << *s;
This ensures your << overloaded operator function is called because the parameters match to it.
Try
std::cout << *s << std::endl;
By the way,
std::cout << s << std::endl;
is not really a random memory location.
It is the actual memory address on the heap, in this case.
You can actually use that address to check the identity of an object.
That's useful while debugging, or in actual code.
For example, if you look at assignment operators, you will often see:
class Foo
{
Foo& operator=( const Foo& foo )
{
// use the identity principle
if ( &foo==this )
return *this; // so I don't waste CPU cycles copying to myself
// ...really do copy here
return *this;
}
};
Although just dereferencing the pointer (i.e. to use '*s' instead of 's') there is a bigger fish to fry! Unless there is a good reason for putting an object on the heap you shouldn't do so:
int main()
{
Snipped s;
std::cout << s << '\n' << s;
}
I found the use of new and more so delete quite rare in the programs I write. Aside from simpler code this conveniently also often yields faster programs. If you really need to allocate something on the heap, use some sort of a smart pointer to make sure the object is automatically released:
int main()
{
std::unique_ptr<Snipped> s(new Snipped);
std::cout << *s << '\n' << *s;
}
As a side note, don't use std::endl either unless you really intend to flush the stream: I found inappropriate use of std::endl to be the root cause of massive performance problems more than once. Sure most of the time it doesn't matter but in even more cases you don't care about the flush. If you don't like using '\n' or "\n" you can instead use a custom manipulator:
std::ostream& nl(std::ostream& out) { return out << '\n'; }
With this you can use nl instead of std::endl and don't suffer from always flushing the stream.

is it possible to pass iostream into a function?

What I mean:
Everyone knows this method of redirecting stream to output:
cout << "sometext"
but is it possible to pass that stream to a function like this:
my_function() << "sometext";
Yes*:
#include <iostream>
#include <ostream>
std::ostream & my_function() { return std::cout; }
// ...
my_function() << "Hello world.\n";
*) Nothing you said in words is entirely correct, and you may well struggle later integrate this into your project, but this answer shows how to make your code do what you want.
Everyone knows this method of redirecting stream to output:
That's not what that does. The stream is called cout; that's the iostream object. The << operator does not redirect anything. The std::ostream objects all have overloaded operator<< functions. Those functions are invoked when you use << with a stream on the left-hand side and some type that has an overload for it on the right.
<< "sometext" is not a "stream" that can be "redirected". It isn't even a valid expression in C++. The << operator is binary. it takes two parameters.
my_function() << "sometext"; can only work if it returns a std::ostream class or something derived from it. Or something that has an overloaded operator<< defined for it and const char*.
cout << "sometext"
This is not "redirecting stream to output" it is invoking the operator << function on the cout object with the string literal "sometext"
if my_function() is returning a ostream which has operator << overloaded then my_function() << "sometext" will compile else it will give an error.
If you are looking for a way to overload << for your own function unrelated to streams, here is how you can do it:
struct MyStruct {
void DoSomething(const string& s);
};
MyStruct &operator<<(MyStruct &x, const string& s) {
x.DoSomething(s);
return x;
}
MyStruct& my_function() {
return MyStruct;
}
int main() {
my_function() << "Hello, world!";
}
In this example, DoSomething will be called on the instance of MyStruct returned from my_function, and "Hello, world!" will be passed to it as an argument.
If I understand what you are asking about, the closest equivalent of a shell redirect for a function that uses std::cout for output is probably to switch temporarily std::cout's internal stream buffer for a different one.
Of course, this is inherently not thread safe and won't cope if the function itself expects std::cout and stdout to be the same underlying thing.
#include <iostream>
#include <sstream>
int main()
{
std::stringbuf redir( std::ios_base::out );
std::streambuf* save = std::cout.rdbuf( &redir );
my_function(); // cout output ends up in redir
std::cout.rdbuf( save ); // restore original cout
}

Overload handling of std::endl?

I want to define a class MyStream so that:
MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
gives output
[blah]123
[blah]56
[blah]78
Basically, I want a "[blah]" inserted at the front, then inserted after every non terminating std::endl?
The difficulty here is NOT the logic management, but detecting and overloading the handling of std::endl. Is there an elegant way to do this?
Thanks!
EDIT: I don't need advice on logic management. I need to know how to detect/overload printing of std::endl.
What you need to do is write your own stream buffer: When the stream buffer is flushed you output you prefix characters and the content of the stream.
The following works because std::endl causes the following.
Add '\n' to the stream.
Calls flush() on the stream
This calls pubsync() on the stream buffer.
This calls the virtual method sync()
Override this virtual method to do the work you want.
#include <iostream>
#include <sstream>
class MyStream: public std::ostream
{
// Write a stream buffer that prefixes each line with Plop
class MyStreamBuf: public std::stringbuf
{
std::ostream& output;
public:
MyStreamBuf(std::ostream& str)
:output(str)
{}
~MyStreamBuf() {
if (pbase() != pptr()) {
putOutput();
}
}
// When we sync the stream with the output.
// 1) Output Plop then the buffer
// 2) Reset the buffer
// 3) flush the actual output stream we are using.
virtual int sync() {
putOutput();
return 0;
}
void putOutput() {
// Called by destructor.
// destructor can not call virtual methods.
output << "[blah]" << str();
str("");
output.flush();
}
};
// My Stream just uses a version of my special buffer
MyStreamBuf buffer;
public:
MyStream(std::ostream& str)
:std::ostream(&buffer)
,buffer(str)
{
}
};
int main()
{
MyStream myStream(std::cout);
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}
> ./a.out
[blah]123
[blah]56
[blah]78
>
Your overloaded operators of the MyStream class have to set a previous-printed-token-was-endl flag.
Then, if the next object is printed, the [blah] can be inserted in front of it.
std::endl is a function taking and returning a reference to std::ostream. To detect it was shifted into your stream, you have to overload the operator<< between your type and such a function:
MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
std::cout << f;
if( f == std::endl )
{
_lastTokenWasEndl = true;
}
return *this;
}
Agreed with Neil on principle.
You want to change the behavior of the buffer, because that is the only way to extend iostreams. endl does this:
flush(__os.put(__os.widen('\n')));
widen returns a single character, so you can't put your string in there. put calls putc which is not a virtual function and only occasionally hooks to overflow. You can intercept at flush, which calls the buffer's sync. You would need to intercept and change all newline characters as they are overflowed or manually synced and convert them to your string.
Designing an override buffer class is troublesome because basic_streambuf expects direct access to its buffer memory. This prevents you from easily passing I/O requests to a preexisting basic_streambuf. You need to go out on a limb and suppose you know the stream buffer class, and derive from it. (cin and cout are not guaranteed to use basic_filebuf, far as I can tell.) Then, just add virtual overflow and sync. (See ยง27.5.2.4.5/3 and 27.5.2.4.2/7.) Performing the substitution may require additional space so be careful to allocate that ahead of time.
- OR -
Just declare a new endl in your own namespace, or better, a manipulator which isn't called endl at all!
I use function pointers. It sounds terrifying to people who aren't used to C, but it's a lot more efficient in most cases. Here's an example:
#include <iostream>
class Foo
{
public:
Foo& operator<<(const char* str) { std::cout << str; return *this; }
// If your compiler allows it, you can omit the "fun" from *fun below. It'll make it an anonymous parameter, though...
Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; }
} foo;
int main(int argc,char **argv)
{
foo << "This is a test!" << std::endl;
return 0;
}
If you really want to you can check for the address of endl to confirm that you aren't getting some OTHER void/void function, but I don't think it's worth it in most cases. I hope that helps.
Instead of attempting to modify the behavior of std::endl, you should probably create a filtering streambuf to do the job. James Kanze has an example showing how to insert a timestamp at the beginning of each output line. It should require only minor modification to change that to whatever prefix you want on each line.
I had the same question, and I thought that Potatoswatter's second answer had merit: "Just declare a new endl in your own namespace, or better, a manipulator which isn't called endl at all!"
So I found out how to write a custom manipulator which is not hard at all:
#include <sstream>
#include <iostream>
class log_t : public std::ostringstream
{
public:
};
std::ostream& custom_endl(std::ostream& out)
{
log_t *log = dynamic_cast<log_t*>(&out);
if (log)
{
std::cout << "custom endl succeeded.\n";
}
out << std::endl;
return out;
}
std::ostream& custom_flush(std::ostream& out)
{
log_t *log = dynamic_cast<log_t*>(&out);
if (log)
{
std::cout << "custom flush succeeded.\n";
}
out << std::flush;
return out;
}
int main(int argc, char **argv)
{
log_t log;
log << "custom endl test" << custom_endl;
log << "custom flush test" << custom_flush;
std::cout << "Contents of log:\n" << log.str() << std::endl;
}
Here's the output:
custom endl succeeded.
custom flush succeeded.
Contents of log:
custom endl test
custom flush test
Here I've created two custom manipulators, one that handles endl and one that handles flush. You can add whatever processing you want to these two functions, since you have a pointer to the log_t object.
You can't change std::endl - as it's name suggests it is a part of the C++ Standard Library and its behaviour is fixed. You need to change the behaviour of the stream itself, when it receives an end of line . Personally, I would not have thought this worth the effort, but if you want to venture into this area I strongly recommend reading the book Standard C++ IOStreams & Locales.

stringstream temporary ostream return problem

I'm creating a logger with the following sections:
// #define LOG(x) // for release mode
#define LOG(x) log(x)
log(const string& str);
log(const ostream& str);
With the idea to do:
LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);
This all works as intended, but when I do:
LOG(stringstream() << "Testing" << 1 << "two" << 3);
It does not work:
void log(const ostream& os)
{
std::streambuf* buf = os.rdbuf();
if( buf && typeid(*buf) == typeid(std::stringbuf) )
{
const std::string& format = dynamic_cast<std::stringbuf&>(*buf).str();
cout << format << endl;
}
}
results in 'format' containing junk data instead of the usual correct string.
I think this is because the temporary ostream returned by the << operator outlives the stringstream it comes from.
Or am I wrong?
(Why does string() work in this way? Is it because it returns a reference to itself? I'm assuming yes.)
I would really like to do it this way as I would be eliminating an additional allocation when logging in release mode.
Any pointers or tricks to get it done this way would be welcomed. In my actual solution I have many different log functions and they are all more complex than this. So I would prefer to have this implemented somehow in the calling code. (And not by modifying my #define if possible)
Just to give an idea, an example of one of my actual #defines:
#define LOG_DEBUG_MSG(format, ...) \
LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( #__VA_ARGS__ )), \
format, __VA_ARGS__)
which matches varargs printf-like log functions taking char*, string() and ostream() as well as non-vararg functions taking string(), exception() and HRESULT.
I think I see what's happening. This produces the expected output:
log(std::stringstream() << 1 << "hello");
while this does not:
log(std::stringstream() << "hello" << 1);
(it writes a hex number, followed by the "1" digit)
A few elements for the explanation:
An rvalue cannot be bound to a non-const reference
It is OK to invoke member functions on a temporary
std::ostream has a member operator<<(void*)
std::ostream has a member operator<<(int)
For char* the operator is not a member, it is operator<<(std::ostream&, const char*)
In the code above, std::stringstream() creates a temporary (an rvalue). Its lifetime is not problematic, as it must last for the whole full expression it is declared into (i.e, until the call to log() returns).
In the first example, everything works ok because the member operator<<(int) is first called, and then the reference returned can be passed to operator<<(ostream&, const char*)
In the second example, operator<<(cannot be called with "std::stringstream()" as a 1st argument, as this would require it to be bound to a non-const reference. However, the member operator<<(void*) is ok, as it is a member.
By the way: Why not define the log() function as:
void log(const std::ostream& os)
{
std::cout << os.rdbuf() << std::endl;
}
Alter your LOG() macro to this:
#define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0)
That will let you use the following syntax in your debugging logs, so you don't have to manually construct the string stream.
LOG("Testing" << 1 << "two" << 3);
Then define it to nothing for release, and you'll have no extra allocations.