C++ object lifetime

Started by
5 comments, last by Zahlman 16 years, 11 months ago
Consider this:
class LogWriter
{
public:
	~LogWriter()
	{
		m_out << std::endl;
		std::cout << m_out.str();
	}

	template < class T >
	LogWriter &operator<<( T t ) 
	{
		m_out << t;
		return *this;
	}
private:
	std::stringstream m_out;
};


class Logger
{
public:
	LogWriter info()
	{
		return LogWriter();
	}
};

int main(int argc, char* argv[])
{
	Logger l;
	l.info() << "Hello " << "World " << 15 << 'x' << " abc";
        return 0;
}

Calling a logging method ( info() ) creates a LogWriter object for the duration of the statement. LogWriter composes the log and writes out entire log in its destructor in one go. LogWriter does not get copied in return LogWriter(); I've tested with debug and release mode under mvc2005 and it behaves as expected. No double logs, no other issues, logs apear exactly when they should. But: Am I abusing something here? Somehow I'm not too happy with all that return-by-value thing. Anyone got an insight to offer?
Advertisement
Looks fine to me. Although you'd probably want to make Logger a friend of LogWriter, and make the LogWriter constructor private to prevent code just creating LogWriter's whenever it wants (Unless you want to do that).
Quote:Original post by Antheus
LogWriter does not get copied in return LogWriter();


Are you sure?

--smw

Stephen M. Webb
Professional Free Software Developer

Why not just keep writers as members of the logger, and return a pointer? Then you could have a "commit" method (or "flush" and anything else) to allow explicit writing, rather than use the end-of-life approach?

That sounds safer to me.
Quote:Original post by smitty1276
Why not just keep writers as members of the logger, and return a pointer? Then you could have a "commit" method (or "flush" and anything else) to allow explicit writing, rather than use the end-of-life approach?

That sounds safer to me.


So that I can return a dummy template that does nothing, and gets compiled out entirely if logger's level is higher than that particular log.

In full implementation, if a logger's level is < default level, every log statement doesn't get evaluated and doesn't generate any code. This way the low level debug logs don't even get put into executable.

Another reason is thread-safety. Having one writer only would require locking.
What about this? It is basically the same, but suggests some possible improvements:
    {        Logger l;        {            LogWriter w = l.info();            w << "Hello " << "World ";            for ( int i = 10; i > 0; --i )            {                w << i << "...";            }            w << 15 << 'x' << " abc";        }        return 0;    } 


Quote:Original post by Antheus
LogWriter does not get copied in return LogWriter();

It may or may not get copied. It depends on the compiler and the optimization level.

As a side note, you might want to make this change:
    template < class T >    LogWriter & operator<<( T const & t )     { 


[Edited by - JohnBolton on May 2, 2007 1:53:22 PM]
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
This sort of thing is actually pretty standard design. The only thing I'd note is that you don't really need another class to implement that kind of object-creational pattern.

This topic is closed to new replies.

Advertisement