I'm writing some code which handles a lot of data. When an error occures, it usually happens that the error will occur many times, so I want to report it only once. The problem I have is, that I want to have individual error messages. In C I would use a method with variadic arguments, bit of course this is not really typesafe, so I wonder how I can achieve the same in C++ with typesafe output. I know that I can stringstream and create the indvidual string, but that would mean that I have to create the full error message, even if it is discarded, because it was already printed, and stringstream is not exactly fast either.
So currently I use code like this:
std::string key = "BT:EMPTY";
if(mErrorReport.find(key) == mErrorReport.end())
{
std::cerr << "ERROR [" << Name<< "] Type is empty! " << std::endl;
mErrorReport.insert(key);
}
std::string key = "UI:"+Unitcode;
if(mErrorReport.find(key) == mErrorReport.end())
{
std::cerr << "ERROR [" << Name<< "] Room with the id " << Unitcode << " doesn't exist! " << std::endl;
mErrorReport.insert(key);
}
...
In C I would have written a variadic function like this:
void ErrorLog(const char *key, int nLogLevel, const char fmt, ...)
{
// Check if this error was already reported before.
if(mErrorLog.find(key) == mErrorLog.end())
{
fprintf(stderr, fmt, ...);
mErrorLog.insert(key);
}
}
So I wonder if there is some best practice for something like that.
Why don't you just use
void ErrorLog(const std::string& key, const std::string& name, const std::string& what)
{
if (mErrorLog.find(key) == mErrorLog.end())
{
std::cerr << "ERROR[" << name << "]" << what << std::endl;
mErrorLog.insert(key);
}
}
and call it like
ErrorLog("BT:EMPTY", Name, "Type is empty!");
ErrorLog("UI:" + Unitcode, Name, std::string("Room with the id ") + Unitcode + " doesn't exist!");
If Name doesn't change you could remove the parameter and just add it to the std::err call.
Update: Alternative solution
class ErrorLogWriter
{
public:
ErrorLogWriter(const std::string& name, const std::string& key, std::set<std::string>& log)
:m_name(name)
, m_key(key)
, m_log(log)
{}
ErrorLogWriter& operator<<(const std::string& msg)
{
if (m_log.find(m_key) == m_log.end())
{
std::cerr << "ERROR[" << m_name << "]" << msg << std::endl;
m_log.insert(m_key);
}
return *this;
}
private:
std::string m_name;
std::string m_key;
std::set<std::string>& m_log;
};
class ErrorLog
{
public:
ErrorLog(const std::string& name, std::set<std::string>& log)
:m_name(name)
,m_log(log)
{}
ErrorLogWriter operator()(const std::string& key)
{
return ErrorLogWriter(m_name, key, m_log);
}
private:
std::string m_name;
std::set<std::string>& m_log;
};
int main()
{
std::string Name = "NAME";
std::string Unitcode = "UNITCODE";
std::set<std::string> mErrorLog;
ErrorLog log(Name, mErrorLog);
log("BT:EMPTY") << "Type is empty!";
log("UI:" + Unitcode) << "Room with the id " << Unitcode << " doesn't exist!";
}
Related
To understand the better about what is best among std::string or std::stringstream while is string manipulation involved. The below code can be replaced with std::string and it's append().
Let's consider the below function.
std::string function(const std::vector<std::string>& param1, const std::string& param2)
{
std::stringstream streamTemp;
if (!param1.empty())
{
for (const auto& item : param1)
{
if (streamTemp.tellp() > 0)
{
streamTemp<<" || ";
}
streamTemp << param2 << " (" << item << ") ";
}
streamTemp<<" (" streamTemp + ") ";
}
return streamTemp.str();
}
With strings, you can append char, char[] or another std::string. But std::stringstream you can append any type that has a suitable operator<<, such as int and float.
This is an assignment of mine that I picked to do but I am not sure how to fix the error message I am getting at cout << contact.getInformation() << endl;without changing the Void function to a different type or changing the main function (which I am trying to avoid). I think my lack of understanding is in how cout and void functions work together. I tried to remove the cout from the function but that did not work and the only way I could make the code run was when I replaced cout << contact.getInformation() << endl; with contact.getInformation() which I am trying to avoid. I just want the inside of the void function to print when I call cout << contact.getInformation() << endl;
Any help is welcome! Thank you!
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Contact{
public:
Contact(int id, string name, string telephone, int age)
: _id{ id }, _name{ name }, _telephone{ telephone }, _age{ age } {}
int id() { return _id; }
string name() { return _name; }
string telephone() { return _telephone; }
int age() { return _age; }
void getInformation() {
cout << "ID: " + to_string(_id) + "\n" +
"NAME: " + _name + "\n" +
"TEL: " + _telephone + "\n" +
"AGE: " + to_string(_age) + "\n";
}
private:
int _id;
string _name;
string _telephone;
int _age;
};
int main() {
Contact contact{1, "Michael", "555-555-5555", 15};
cout << contact.getInformation() << endl;
}.
EDIT: Thanks all! I see now that it is impossible to do with those restrictions.
The code you've provided have many issues. You can avoid them if you read some good C++ book, my advice is Scott Meyers Effective C++: 55 Specific Ways to Improve Your Programs and Designs.
don't use using directive unless really necessary. In most cases for std namespace - it is not.
Pass function arguments of non primitive type by reference/const reference rather by value or pointer
Understand const keyword and it usage
Understand constructor static initialization bocks
Understand c++ streams
This is how you code should looks like:
#include <iostream>
#include <string>
class Contact {
public:
Contact(int id,const std::string& name,const std::string& telephone, int age):
_id( id ),
_name( name ),
_telephone( telephone ),
_age( age )
{}
int id() const {
return _id;
}
std::string name() const {
return _name;
}
std::string telephone() const {
return _telephone;
}
int age() const {
return _age;
}
private:
int _id;
std::string _name;
std::string _telephone;
int _age;
};
std::ostream& operator<<(std::ostream& to,const Contact& c)
{
to << "ID: " << c.id() << '\n';
to << "NAME: " << c.name() << '\n';
to << "TEL: " << c.telephone() << '\n';
to << "AGE: " << c.age() << '\n';
to.flush();
return to;
}
int main(int argc, const char** argv)
{
Contact contact = {1, "Michael", "555-555-5555", 15};
std::cout << contact << std::endl;
return 0;
}
What you are asking is not possible. The two conditions you have set (i.e. 1. Do not change the void function to another type, and 2. Do not alter the main method) make it impossible to change your code in some other way so as for the main function to produce the intended outcome.
You can either alter your void function to one that returns something 'printable', e.g. a string, or you can keep your void function printing to cout directly, but then change the main function to call this on its own, outside the context of a cout << construct.
(Or, preferably, as has also been pointed in the comments, instead of void, overload the << operator to make cout work with your specific object type)
The name getInformation suggests it should, well, get the information and not print it.
Therefore you probably want this:
string getInformation() {
return "ID: " + to_string(_id) + "\n" +
"NAME: " + _name + "\n" +
"TEL: " + _telephone + "\n" +
"AGE: " + to_string(_age) + "\n";
}
Instead of this:
void getInformation() {
cout << "ID: " + to_string(_id) + "\n" +
"NAME: " + _name + "\n" +
"TEL: " + _telephone + "\n" +
"AGE: " + to_string(_age) + "\n";
}
Not changing main nor getInformation is not possible.
I am writing a C++ interface for a line based protocol. The commands are simple, they are structured like this:
<cmd> <args>\n
Some commands have a fixed number of arguments, some have variable ones. I am using ostringstream to assemble the line. I wrote two base classes to cover the commands with and without variable arguments:
class format_command
{
public:
explicit format_command(std::string const &p_cmd_name)
{
m_sstream << p_cmd_name;
}
std::string get_string() const;
protected:
std::ostringstream m_sstream;
};
class format_command_with_args
: public format_command
{
public:
explicit format_command_with_args(std::string const &p_cmd_name)
{
m_sstream << p_cmd_name;
}
template < typename T >
format_command_with_args& operator << (T const &p_value)
{
m_sstream << " " << p_value;
return *this;
}
};
Individual command line generators are then derived as needed. Let's take two example commands, foo and bar. foo takes a fixed number of arguments, bar variable ones.
class format_foo
: public format_command
{
public:
explicit format_foo(std::string const &p_string, int const p_number)
: format_command("foo")
{
m_sstream << " " << p_string << " " << p_number;
}
};
class format_bar
: public format_command_with_args
{
public:
explicit format_bar(float const p_decimal, char const p_char)
: format_command("bar")
{
m_sstream << " " << p_decimal << " " << p_char;
}
};
And then I have functions that create instances of these classes.
namespace command
{
format_foo foo(std::string const &p_string, int const p_number)
{
return format_foo(p_string, p_number);
}
format_bar bar(float const p_decimal, char const p_char)
{
return format_foo(p_decimal, p_char);
}
}
I can then do this:
std::string command_str = command::foo("hello", 11).get_string();
std::string command_str = (command::bar(1.2f, 'x') << "extra-arg" << "another-arg").get_string();
I added this indirection through the command:: functions because some commands are like this:
somecmd <arg1> <arg2> [<arg3> [<varargs>]]
meaning that they have variable arguments only if a specific argument is present. So, if the third argument isn't present, I want to make sure that the user cannot add extra variable arguments with the stream operator. In such cases, I can then do this:
class format_somecmd
: public format_command
{
public:
explicit format_somecmd(std::string const &p_arg1, std::string const &p_arg2)
: format_somecmd("bar")
{
m_sstream << " " << p_arg1 << " " << p_arg2;
}
};
class format_somecmd_with_args
: public format_command_with_args
{
public:
explicit format_somecmd_with_args(std::string const &p_arg1, std::string const &p_arg2, std::string const &p_arg3)
: format_somecmd("bar")
{
m_sstream << " " << p_arg1 << " " << p_arg2 << " " << p_arg3;
}
};
namespace command
{
format_somecmd somecmd(std::string const &p_arg1, std::string const &p_arg2)
{
return format_somecmd(p_arg1, p_arg2);
}
format_somecmd_with_args somecmd(std::string const &p_arg1, std::string const &p_arg2, std::string const &p_arg3)
{
return format_somecmd_with_args(p_arg1, p_arg2, p_arg3);
}
This way, I can do this:
std::string command_str = command::somecmd("hello", "world").get_string();
std::string command_str = (command::somecmd("hello", "world", "test") << "extra-arg" << "another-arg").get_string();
and this fails at compile time (which is intentional since it would be an invalid command):
std::string command_str = (command::somecmd("hello", "world") << "extra-arg" << "another-arg").get_string();
This works well so far. The part that bothers me though is the .get_string(). I have considered using operator std::string(), but this seems like a can of worms.
Any suggestions on how to improve it, particularly with regards to get_string() ?
I currently read the book Effective C++ from Scott Meyers. It says I should prefer inline functions over #define for function-like macros.
Now I try to code an inline function to replace my exception macro. My old macro looks like this:
#define __EXCEPTION(aMessage) \
{ \
std::ostringstream stream; \
stream << "EXCEPTION: " << aMessage << ", file " <<__FILE__ << " line " << __LINE__; \
throw ExceptionImpl(stream.str()); \
}
My new inline function is this:
inline void __EXCEPTION(const std::string aMessage)
{
std::ostringstream stream;
stream << "EXCEPTION: " << aMessage << ", file " <<__FILE__ << " line " << __LINE__;
throw ExceptionImpl(stream.str());
}
As probably some people already expect, now the __FILE__ and __LINE__ macros are useless, because they refer always to the C++-file with the definition of the inline function.
Is there any way to circumvent this behaviour or should I stick with my old macro? I read this threads here, and I already suspect that there is probably no way of my second example to work fine:
Behavior of __LINE__ in inline functions
__FILE__, __LINE__, and __FUNCTION__ usage in C++
Don't use __ (double underscore) as it's reserved. Having an inline function is better.
However, here you need a mix of macro and the function, hence you can do following:
#define MY_EXCEPTION(aMessage) MyException(aMessage, __FILE__, __LINE__)
inline void MyException(const std::string aMessage,
const char* fileName,
const std::size_t lineNumber)
{
std::ostringstream stream;
stream << "EXCEPTION: " << aMessage << ", file " << fileName << " line " << lineNumber;
throw ExceptionImpl(stream.str());
}
I see this is an old question but I think that the approach of printing the line in the exception macro is fundamentally flawed and I think I have a better alternative. I assume that the macro is used similar to the following code:
try {
/// code
throw;
}
catch (...) { __EXCEPTION(aMessage); }
With this approach the macro prints the location where the exception was catch'ed. But for troubleshooting and debugging the location where it was throw'n is usually more useful.
To get that information, we can attach the __FILE__ and __LINE__ macros to the exception. However, we still can't get completely rid of macros, but we get at least the exact throw location:
#include <iostream>
#include <exception>
#include <string>
#define MY_THROW(msg) throw my_error(__FILE__, __LINE__, msg)
struct my_error : std::exception
{
my_error(const std::string & f, int l, const std::string & m)
: file(f)
, line(l)
, message(m)
{}
std::string file;
int line;
std::string message;
char const * what() const throw() { return message.c_str(); }
};
void my_exceptionhandler()
{
try {
throw; // re-throw the exception and capture the correct type
}
catch (my_error & e)
{
std::cout << "Exception: " << e.what() << " in line: " << e.line << std::endl;
}
}
int main()
{
try {
MY_THROW("error1");
} catch(...) { my_exceptionhandler(); }
}
There is one additional improvement possible if we are willing to use boost::exception: We can get rid of macro definitons at least in our own code. The whole program gets shorter and the locations of code execution and error handling can be nicely separated:
#include <iostream>
#include <boost/exception/all.hpp>
typedef boost::error_info<struct tag_error_msg, std::string> error_message;
struct error : virtual std::exception, virtual boost::exception { };
struct my_error: virtual error { };
void my_exceptionhandler()
{
using boost::get_error_info;
try {
throw;
}
catch(boost::exception & e)
{
char const * const * file = get_error_info<boost::throw_file>(e);
int const * line = get_error_info<boost::throw_line>(e);
char const * const * throw_func = get_error_info<boost::throw_function>(e);
std::cout << diagnostic_information(e, false)
<< " in File: " << *file << "(" << *line << ")"
" in Function: " << *throw_func;
}
}
int main()
{
try {
BOOST_THROW_EXCEPTION(my_error() << error_message("Test error"));
} catch(...) { my_exceptionhandler(); }
}
Please consider that there is another difference between using the #define function-like macro in your case in comparison to inline functions. You could have used streaming operators and parameters in your macro's invocation to be composed as your message's text:
__EXCEPTION( "My message with a value " << val )
But most times I've needed something like this, it was to check on a certain condition (like an assertion). So you could extend #iammilind's example with something like:
#define MY_EXCEPTION_COND( cond ) \
if (bool(cond) == false) \
{ \
std::string _s( #cond " == false" ); \
MyException(_s, __FILE__, __LINE__); \
}
Or something a little more specialized where the values are also printed:
template <typename T>
inline void MyExceptionValueCompare(const T& a,
const T& b,
const char* fileName,
const std::size_t lineNumber)
{
if (a != b)
{
std::ostringstream stream;
stream << "EXCEPTION: " << a << " != " << b << ", file " << fileName << " line " << lineNumber;
throw ExceptionImpl(stream.str());
}
}
#define MY_EXCEPTION_COMP( a, b ) MyExceptionValueCompare(a, b, __FILE__, __LINE__)
Another approach you may want to take a look at is Microsoft's usage of their __LineInfo class in the Microsoft::VisualStudio::CppUnitTestFramework namespace (VC\UnitTest\Include\CppUnitTestAssert.h). See https://msdn.microsoft.com/en-us/library/hh694604.aspx
With std::experimental::source_location, you might do:
#include <experimental/source_location>
void THROW_EX(const std::string_view& message,
const std::experimental::source_location& location
= std::experimental::source_location::current())
{
std::ostringstream stream;
stream << "EXCEPTION: " << message
<< ", file " << location.file_name()
<< " line " << location.line();
throw ExceptionImpl(stream.str());
}
How can I derive a class from cout so that, for example, writing to it
new_cout << "message";
would be equivalent to
cout << __FUNCTION__ << "message" << "end of message" << endl;
class Log
{
public:
Log(const std::string &funcName)
{
std::cout << funcName << ": ";
}
template <class T>
Log &operator<<(const T &v)
{
std::cout << v;
return *this;
}
~Log()
{
std::cout << " [end of message]" << std::endl;
}
};
#define MAGIC_LOG Log(__FUNCTION__)
Hence:
MAGIC_LOG << "here's a message";
MAGIC_LOG << "here's one with a number: " << 5;
#define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl)
This has the advantage that you can disable all debug messages at once when you're done
#define debug_print(message) ()
Further from Mykola's response, I have the following implementation in my code.
The usage is
LOG_DEBUG("print 3 " << 3);
prints
DEBUG (f.cpp, 101): print 3 3
You can modify it to use FUNCTION along/in place of LINE and FILE
/// Implements a simple logging facility.
class Logger
{
std::ostringstream os_;
static Logger* instance_;
Logger();
public:
static Logger* getLogger();
bool isDebugEnabled() const;
void log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const;
std::ostringstream& getStream()
{ return os_; }
};
void Logger::log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const
{
std::cout << logLevelEnumToString(l) << "\t(" << fileName << ": " << lineno << ")\t- " << os.str();
os.str("");
}
#define LOG_common(level, cptext) do {\
utility::Logger::getLogger()->getStream() << cptext; \
utility::Logger::getLogger()->log(utility::level, utility::Logger::getLogger()->getStream(), __FILE__, __LINE__); \
} while(0);
enum LogLevelEnum {
DEBUG_LOG_LEVEL,
INFO_LOG_LEVEL,
WARN_LOG_LEVEL,
ERROR_LOG_LEVEL,
NOTICE_LOG_LEVEL,
FATAL_LOG_LEVEL
};
#define LOG_DEBUG(cptext) LOG_common(DEBUG_LOG_LEVEL, cptext)
#define LOG_INFO(cptext) LOG_common(INFO_LOG_LEVEL , cptext)
#define LOG_WARN(cptext) LOG_common(WARN_LOG_LEVEL , cptext)
#define LOG_ERROR(cptext) LOG_common(ERROR_LOG_LEVEL, cptext)
#define LOG_NOTICE(cptext) LOG_common(NOTICE_LOG_LEVEL, cptext)
#define LOG_FATAL(cptext) LOG_common(FATAL_LOG_LEVEL, cptext)
const char* logLevelEnumToString(LogLevelEnum m)
{
switch(m)
{
case DEBUG_LOG_LEVEL:
return "DEBUG";
case INFO_LOG_LEVEL:
return "INFO";
case WARN_LOG_LEVEL:
return "WARN";
case NOTICE_LOG_LEVEL:
return "NOTICE";
case ERROR_LOG_LEVEL:
return "ERROR";
case FATAL_LOG_LEVEL:
return "FATAL";
default:
CP_MSG_ASSERT(false, CP_TEXT("invalid value of LogLevelEnum"));
return 0;
}
}
For logging purposes I use something like
#define LOG(x) \
cout << __FUNCTION__ << x << endl
// ...
LOG("My message with number " << number << " and some more");
The problem with your approach is (as Mykola Golybyew explained) that FUNCTION is processed at compile time and would therefore always print the same name with a non-preprocessor solution.
If it's only for adding endl to your messages, you could try something like:
class MyLine {
public:
bool written;
std::ostream& stream;
MyLine(const MyLine& _line) : stream(_line.stream), written(false) { }
MyLine(std::ostream& _stream) : stream(_stream), written(false) { }
~MyLine() { if (!written) stream << "End of Message" << std::endl; }
};
template <class T> MyLine operator<<(MyLine& line, const T& _val) {
line.stream << _val;
line.written = true;
return line;
}
class MyStream {
public:
std::ostream& parentStream;
MyStream(std::ostream& _parentStream) : parentStream(_parentStream) { }
MyLine getLine() { return MyLine(parentStream); }
};
template <class T> MyLine operator<<(MyStream& stream, const T& _val) {
return (stream.getLine() << _val);
}
int main()
{
MyStream stream(std::cout);
stream << "Hello " << 13 << " some more data";
stream << "This is in the next line " << " 1 ";
return 0;
}
Note, that it's important not to return references from the operator functions. Since the MyLine should only exist as a temporary (for its destructor triggers the writing of the endl), the first object (returned by the getLine() function in MyStream) would be destructed before the second operator<< is called. Therefore the MyLine object is copied in each operator<< creating a new one. The last object gets destructed without being written to and writed the end of the message in its destructor.
Just try it out in the debugger to understand whats going on...
You have to override operator<<(), but you even don't have to subclass std::cout. You may also create a new object or use existing objects like that.
You could also override the operator. It will allow you to call another function or prefix/suffix anything that's going to leave the output buffer with whatever you wish: In your case, you'd have it output a specific string.