I have a class in C++ on Linux that allows me to display messages on the console, depending on where the application is running. If it works in my computer, the messages displayed in console mode. Otherwise, everything is recorded in a text file for later viewing. And I created an extern object to use it. I wanted to try to make this class a singleton, but without success. I have this error appears to be when I come to compile my program:
error: invalid operands of types ‘Log *’ and ‘const char [12]’ to binary ‘operator <<‘
And also:
error: no match for ‘operator <<‘ in ‘logOutput’ << Buffer_T ….
I would like your opinion. Thank you in advance for your attention.
My functional class currently
typedef std::vector<unsigned char> Buffer_T;
class Log
{
public:
Log();
virtual ~Log();
void init()
{
#indef FriendlyArm
output = new ofstream("/home/arm/Log.txt");
#else
output = &cout;
#endif
}
template<typename T>
Log operator<<( T const& value )
{
(*output) << value;
return *this;
}
Log& operator<<( std::ostream&(*f)(std::ostream&) )
{
(*output) << f;
return *this;
}
Log& operator<<(Buffer_T& Buf)
{
if( Buf.size() > 0 )
{
for( unsigned int i = 0; i < Buf.size(); i++ )
{
if( Buf[i] >= 32 && Buf[i] <= 127 )
{
(*output) << Buf[i];
}
else
{
(*output) << "0x" << std::setfill( '0' ) << std::hex << std::setw( 2 ) << unsigned( Buf[i] );
}
}
}
return *this;
}
private:
ostream *output;
};
#endif /* LOG_H_ */
And here is my attempt to singleton
typedef std::vector<unsigned char> Buffer_T;
class Log
{
public:
static Log *createOrGet()
{
if(_unique == NULL)
{
_unique = new Log();
}
return _unique;
}
static void kill()
{
if(_unique != NULL)
{
delete _unique;
_unique = NULL;
}
}
void init()
{
#indef FriendlyArm
output = new ofstream("/home/arm/Log.txt");
#else
output = &cout;
#endif
}
template<typename T>
Log operator<<( T const& value )
{
(*output) << value;
return *this;
}
Log& operator<<( std::ostream&(*f)(std::ostream&) )
{
(*output) << f;
return *this;
}
Log& operator<<(Buffer_T& Buf)
{
if( Buf.size() > 0 )
{
for( unsigned int i = 0; i < Buf.size(); i++ )
{
if( Buf[i] >= 32 && Buf[i] <= 127 )
{
(*output) << Buf[i];
}
else
{
(*output) << "0x" << std::setfill( '0' ) << std::hex << std::setw( 2 ) << unsigned( Buf[i] );
}
}
}
return *this;
}
private:
Log();
virtual ~Log();
static Log *_unique;
ostream *output;
};
Log *Log::_unique = NULL;
#endif
Important: Don’t take it the wrong way, but you make some mistakes that show you’re not very experienced and singletons are very hard to use properly. In the case of a logger they are okay, just make sure to always use them as a last resort.
I don’t have the time to go over why
operator<<isn’t working for you, but here’s some tips on how to improve your singleton (you also seem to be asking for advice on that).The Instance function
That’s called Meyer’s singleton. For single threaded application it’s great: the instance gets created on the first call of the function and automatically gets destroyed when the application closes (you don’t need a
killfunction).Your private virtual destructor
I notice you have a private virtual destructor. You only need a virtual destructor when there’s at least one other virtual function in the class. This is not the case; make the destructor non-virtual.
Enforcing a single instance
You made the constructor private — that’s good, you are preventing me from directly creating multiple instances of the singleton. However you did not prevent me from making copies of the existing singleton. To also prevent that you also need to make the CopyConstructor and AssignmentOperator non-public:
(The destructor should also be private in order to prevent me from deleting the only instance of the class.)
Also notice I made them
protected, notpublic. If you don’t know the difference, look it up (not enough space to explain here). I made themprotectedso you could inherit from theLogclass if you need to.