I am writing my own Logger. I know there are alot out there but i would like to write it myself. It has messages which get logged when they are leaving the scope. So if i call Logger::Error(__FILE__,__LINE__) << "some error" it gets logged directly since there is no assignemnt to a variable.
But i would like to have a message which logs the time of the scope. So it mesures the time since creation and since delete. Therefore i need it to be assigned to a variable in the scope with for example this marko: #define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__)
It can be used like this:
int main()
{
{
LOG_SCOPE_TIME << "Some scope";
//do something to mesure
}
}
Example output:
[timer][File:main.cpp][Line:19][thread:8024][21-05-2015][13:15:11] Some scope[0µs]
[timer][File:main.cpp][Line:19][thread:8788][21-05-2015][13:15:11] Some scope[118879µs]
But this actually causes 2 logs. The first of the temporary created LogTime object (with time 0µs) and the second with the real scope time.
How do i prevent from this? Any suggestions? Here is a reduced example:
#include <iostream>
#include <chrono>
class LogTimer {
std::string str;
std::chrono::high_resolution_clock::time_point m_start;
public:
LogTimer(const std::string& file, int i)
: m_start(std::chrono::high_resolution_clock::now())
{
str = file + ':' + std::to_string(i);
}
~LogTimer() {
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(end - m_start).count();
std::cout << str << " [" << duration << "µs]\n";
}
LogTimer& operator<<(const std::string& p) {
str += '[' + p + ']';
return *this;
}
};
namespace Logger {
LogTimer Timer(const std::string& f, int i) {
return LogTimer(f, i);
}
}
#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__)
int main()
{
LOG_SCOPE_TIME << "something"; // logs two lines
}
You're running into an operator precedence issue, sort of. When you use your macro:
LOG_SCOPE_TIME << "Some scope";
That expands into:
LogTimer ___t = Logger::Timer(__FILE__,__LINE__) << "Some scope";
Which gets evaluated as:
LogTimer ___t = (Logger::Timer(__FILE__,__LINE__) << "Some scope");
since << has higher precedence than =. As such, you are preventing copy elision from happening since the compiler has to now create a temporary Timer to perform the << "Some Scope" and then copy it into ___t (which is technically a reserved name). The additional copy means an addition destructor, which in your case means an extra line logged.
You need to ensure copy elision. The simplest way I can think of is to change your macro to do:
#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__); ___t
That way, your original example expands to:
LogTimer ___t = Logger::Timer(__FILE__,__LINE__); ___t << "Some scope";
No issues there.
Related
I'm just comparing the performance of passing a string to a function. The benchmark results are interesting.
Here's my code:
void add(std::string msg)
{
msg += "world";
}
void addRvalue(std::string&& msg)
{
msg += "world";
}
void addRef(std::string& msg)
{
msg += "world";
}
void StringCreation() {
add(std::string("hello "));
}
void StringCopy() {
std::string msg("hello ");
add(msg);
}
void StringMove() {
std::string msg("hello ");
add(std::move(msg));
}
void StringRvalue() {
std::string msg("hello ");
addRvalue(std::move(msg));
}
void StringReference() {
std::string msg("hello ");
addRef(msg);
}
StringCreation(), StringRvalue() and StringReference() are equivalent. I'm surprised StringMove() is the least performant - worse than pass by value which involves a copy.
Am I right in thinking that calling StringMove() involves one move constructor followed by a copy constructor when it calls add()? It doesn't just involve one move constructor? I thought move construction was cheap for a string.
Update
I increased the length of the string passed to add() and that did make a difference. Now StringMove() is only 1.1 times slower than StringCreation and StringReference. StringCopy is now the worst, which is what I expected.
Here are the new benchmark results.
So StringMove doesn't involve copying after all - only for small strings.
Let's analyze your code and suppose long strings (without applied SSO):
void add(std::string msg) {
msg += "world";
}
void StringCreation() {
add(std::string("hello "));
}
Here, a converting constructor (ConvC) from the string literal is called first to initialize the temporary std::string("hello "). This temporary (an rvalue) is then used to initialize the parameter msg by the move constructor (MC). However, the latter is very likely optimized away by copy elision. Finally, the operator += is called. Bottom line: 1x ConvC and 1x +=.
void StringCopy() {
std::string msg("hello ");
add(msg);
}
Here, the parameter msg is copy-initialized (by copy constructor - CC) by the lvalue argument msg. Bottom line: 1x ConvC, 1x CC, and 1x +=. In case of long strings, this is the slowest version, since copy involves dynamic memory allocations (the only case).
void StringMove() {
std::string msg("hello ");
add(std::move(msg));
}
Why is this slower than StringCreation? Simply because there is an additional MC involved that initializes the parameter msg. It cannot be elided, since the object msg still exist after the call of add. Just it is moved-from. Bottom line: 1x ConvC, 1x MC, 1x +=.
void addRef(std::string& msg) {
msg += "world";
}
void StringReference() {
std::string msg("hello ");
addRef(msg);
}
Here, the operator += is applied to the referenced object, so there is no reason for any copy/move. Bottom line: 1x ConvC, 1x +=. Same time as for StringCreation.
void addRvalue(std::string&& msg) {
msg += "world";
}
void StringRvalue() {
std::string msg("hello ");
addRvalue(std::move(msg));
}
With Clang, the time is same as for StringReference. With GCC, the time is same as for StringMove. In fact, I don't have an explanation for this behavior for now. (It seems to me that GCC is creating some additional temporary initialized by MC. However, I don't know why.)
In this example, none of the functions that are being "benchmarked" are actually doing anything of consequence. That is, none of them actually returns an computed value that is then used elsewhere.
So, any (half-)decent compiler would probably just decide to ignore them completely!
In order for a valid benchmark to be made, then the string results from each/every call must be used for something, even simple output to a file/console.
Try this code to see what's (not) happening:
#include<iostream>
#include<string>
using namespace std;
void add(std::string msg)
{
msg += " + 'add'";
}
void addRef(std::string& msg)
{
msg += " + 'addRef'";
}
void addRvalue(std::string&& msg)
{
msg += " + 'addRefRef'";
}
int main()
{
std::string msg("Initial string!");
cout << msg << endl;
add(msg);
cout << msg << endl; // msg will be the same as before!
addRef(msg);
cout << msg << endl; // msg will be extended!
addRvalue(std::move(msg));
cout << msg << endl; // msg will again be extended
add(std::move(msg));
cout << msg << endl; // msg will be completely emptied!
return 0;
}
So I have that simple code inside button click method:
std::stringstream ss;
unsigned counter = 0;
while(true)
{
ss.clear();
ss << DEFAULT_USER_CONFIG_NAME << " " << ++counter;
const char* name = ss.str().c_str();
MessageBox(name);
/* ... while break condition */
}
The problem is that messagebox is empty. But it works correctly when I pass text directly:
MessageBox(ss.str().c_str()); // that shows text just fine
What I found with debugger is that local variable "name" is not created(at least it is not showing in debugger). Any clue why it is working when passed directly and failing otherwise? Also when i casted "name" to CString it returned true on IsEmpty() check.
The expression ss.str() creates a temporary std::string object. Storing the result of c_str() thus points to memory of a temporary, which quickly turns into a dangling pointer. Once the full expression statement
const char* name = ss.str().c_str();
// ^ this is where the temporary ss.str() gets destroyed.
is evaluated, the temporary gets destroyed.
You already know, how to solve this, by placing the expression creating the temporary inside the full expression, that consumes it. This extends the lifetime of the temporary until the end of the full expression:
MessageBox(ss.str().c_str());
// ^ this is where the temporary ss.str() gets destroyed.
The following illustrates the sequence of events. Let's just define a few placeholder classes and functions:
void messagebox(const char*) {
cout << "messagebox()" << endl;
}
struct tmp {
tmp(const char* content) : content(content) { cout << "tmp c'tor" << endl; }
~tmp() { cout << "tmp d'tor" << endl; }
const char* c_str() { return content.c_str(); }
private:
string content;
};
struct ss {
tmp str() { return tmp("test"); }
};
With this in place, your first version
ss s;
const char* name = s.str().c_str();
messagebox(name);
produces the following output:
tmp c'tor
tmp d'tor
messagebox()
Whereas the second version
ss s;
messagebox(s.str().c_str());
changes the sequence in the output:
tmp c'tor
messagebox()
tmp d'tor
(Live sample code)
I'm tired of making up on the spot debug codes and including <iostream> in every single file. So I wanted to make myself a universal, self-contained and lightweight debug class, that I would just include in the header, and forget.
I want to use something along the lines of
#include "debug.hpp"
debug DBG;
DBG << "foo and" << " bar";
//Or even better, just include it and do debug() << "foo and" << " bar";
So, I wrote this:
#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
class Debug
{
public:
Debug &operator<<(std::string arg_0)
{
auto tempTime = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() );
auto timeString(ctime(&tempTime));
timeString = timeString.substr(timeString.find(':') - 2, 8);
std::cout << timeString << " >> " << arg_0 << '\n';
return *this;
}
};
But of course, this doesn't work because, as I've learned, every overload operator causes this function (is it still called a function?) to trigger separately. Creating:
hour:minute:second >> foo and
hour:minute:second >> bar
Any way I could pass everything at once after the first overload operator appears? Maybe as a stringstream? Also, I won't be only passing strings, but anything that I need, will this require me to manually create a separate overload function for every signle type that I may pass?
P.S: Cross-plaform solution is optional, but welcome (Currently developing on Linux)
You may return an other class to do the job, something like:
class Helper
{
public:
~Helper() { std::cout << "\n"; }
template<typename T>
friend Helper&& operator << (Helper&&h, const T& t) {
std::cout << t;
return std::move(h);
}
};
class Debug
{
public:
template<typename T>
friend Helper operator<<(Debug&, const T& t)
{
auto tempTime = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() );
auto timeString{ctime(&tempTime)};
timeString = timeString.substr(timeString.find(':') - 2, 8);
std::cout << timeString << " >> " << t;
return Helper{};
}
};
Each time you call operator<<, your code prints the time stamp and \n. And that's the problem. To avoid that, you can print the time stamp in the constructor of Debug, and print \n in the destructor.
class Debug {
public:
Debug() {
auto tempTime = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() );
std::string timeString(ctime(&tempTime));
timeString = timeString.substr(timeString.find(':') - 2, 8);
std::cout << timeString;
}
~Debug() {
std::cout << "\n";
}
Debug &operator<<(std::string arg_0) {
std::cout << " >> " << arg_0;
return *this;
}
};
In order to debug types other than string, you make operator<< a template:
template <typename T>
Debug &operator<<(T &&arg_0) {
std::cout << " >> " << std::forward<T>(arg_0);
return *this;
}
I see 2 design problems here:
You try to create stream-like object. It means that it doesn't know, when the line ends, until you send EOL to it. Without this information, it doesn't know when to add prefix to "your" line and print it. Consider the two following situation:
DBG << "foo and" << " bar";
and
DBG << "foo and";
... (a lot of code) ...
DBG << " bar";
They look exactly the same inside your Debug class, because:
DBG << "foo and" << " bar"; == (DBG.operator<<("foo and")).operator<<(" bar");
And this is the same as:
DBG.operator<<("foo and");
DBG.operator<<("bar");
So you have to decide how to define the end of the message you want to print (and when do you want to measure the time: At the beginning or at the end of the message?).
When do you want to flush your stream? You have to send std::endl or std::flush to std::cout to flush it. Sending "\n" does not flush std::cout (this is important difference between std::endl and "\n"). If you do not flush it, it may be printed several minutes/hours later (it will wait in a buffer). On the other hand frequent buffer flushing may be a performance killer in application producing large amount of text.
Try to define how your stream should behave when you send to it "\n", std::endl and std::flush (std::endl should be converted to "\n"+std::flush).
About other questions:
I would use simple template to "transfer" parameter of operator<<() to std::cout. It would allow to use your class for any type that can be printed by std::cout. To make things simpler you can define the operator<<() outside your class, eg.:
template<typename tParam>
Debug &operator<<(Debug& stream, tParam const & myParam)
{
...
return stream;
}
I want to overload a function so that it manipulates its argument in some way and then returns a reference to the argument – but if the argument is not mutable, then it should return a manipulated copy of the argument instead.
After messing around with it for ages, here's what I've come up with.
using namespace std;
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string &&in)
{
return move(foo(in));
}
string foo(const string& in)
{
return foo(string(in));
}
This code seem to work correctly, but I'm interested to hear if anyone can think of a better way to do it.
Here's a test program:
int main(void)
{
string var = "world";
const string var2 = "const world";
cout << foo(var) << endl;
cout << var << endl;
cout << foo(var2) << endl;
cout << var2 << endl;
cout << foo(var + " and " + var2) << endl;
return 0;
}
The correct output is
hello world
hello world
hello const world
const world
hello hello world and const world
I figure it would be slightly neater if I could do this:
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string in)
{
return move(foo(in));
}
Of course, that doesn't work because most function calls to foo would be ambiguous – including the call in foo itself! But if I could somehow tell the compiler to prioritize the first one...
As I said, the code I posted works correctly. The main thing I don't like about it is the repetitive extra code. If I had a bunch of functions like that it would become quite a mess, and most of it would be very repetitive. So as a second part to my question: can anyone think of a way to automatically generate the code for the second and third foo functions? eg
// implementation of magic_function_overload_generator
// ???
string& foo(string &in);
magic_function_overload_generator<foo>;
string& bar(string &in);
magic_function_overload_generator<bar>;
// etc
I would get rid of the references all together and just write one function that passes and returns by value:
std::string foo(std::string in)
{
in.insert(0, "hello ");
return in;
}
If you pass an lvalue, the input string will be copied. If you pass an rvalue, it will be moved.
When leaving the function, named return value optimization will probably kick in, so the return is basically a no-op. If the compiler decides against that, the result will be moved (even though in is an lvalue).
The good thing about rvalue references is that you have to think less about where to put references in user code to gain efficiency. With movable types, pass-by-value is practically as efficient as it gets.
The whole question is why do you want to have such overloads? All these overloads specify one interface: foo(x). But x parameter may be input or input/output parameter depending on its type. It is very, very error-prone. A user shall do some additional job to make sure that its variable won't be mutated. Never do that in production code.
I would agree with such overloads:
string foo(string &&in);
string foo(const string& in);
Input parameter is never changed if it is not a temporary and, at the same time, you reuse temporary objects. It seems quite reasonable.
But, why do you want to generate a lot of such overloads? && overload is for optimization. I would say very delicate optimization. Are you sure you need it in lots of places?
Anyway, if you really want to generate C++ code, templates are not a really good choice. I would use some external tool for it. Personally, I prefer Cog.
What about following simple approach ?
string& foo (string &change) // this accepts mutable string
{
change = string("hello ") + change;
return change;
}
string foo (const string &unchange) // this accepts not mutable string
{
return string("hello ") + unchange;
}
See it's output here.
In the same vein as #iammilind's answer, but sans duplication:
#include <iostream>
using namespace std;
string foo(const string &unchange) {
return string("hello ") + unchange;
}
string& foo(string &change) {
return change = foo(static_cast<const string&>(foo));
}
int main(int argc, char** argv) {
string a = "world";
const string b = "immutable world";
cout << foo(a) << '\n' << foo(b) << '\n';
cout << foo(a) << '\n' << foo(b) << '\n';
}
NB: You could also use const_cast here to add the const qualification.
If you're not worried about efficiency, you can do pass by value or pass by const reference and do a copy and be done with it.
However, if you are worried about efficiency, I don't think the pass by value suggestion in this reply is the best approach. This is because I think it results in extra copies/moves, as NRVO only seems to work with local variables, not parameters. I think the way that avoids moves/copies in C++0x is the dual overloads, as illustrated by the following code:
#include <iostream>
struct A
{
A() : i(0) {}
A(const A& x) : i(x.i) { std::cout << "Copy" << std::endl; }
A(A&& x) : i(x.i) { std::cout << "Move" << std::endl; }
void inc() { ++i; }
int i;
};
A f1(const A& x2) { A x = x2; x.inc(); return x; }
A&& f1(A&& x) { x.inc(); return std::move(x); }
A f2(A x) { x.inc(); return std::move(x); }
int main()
{
A x;
std::cout << "A a1 = f1(x);" << std::endl;
A a1 = f1(x);
std::cout << "A a2 = f1(A());" << std::endl;
A a2 = f1(A());
std::cout << "A b1 = f2(x);" << std::endl;
A b1 = f2(x);
std::cout << "A b2 = f2(A());" << std::endl;
A b2 = f2(A());
std::cout << std::endl;
std::cout << "A a3 = f1(f1(x));" << std::endl;
A a3 = f1(f1(x));
std::cout << "A a4 = f1(f1(A()));" << std::endl;
A a4 = f1(f1(A()));
std::cout << "A b3 = f2(f2(x));" << std::endl;
A b3 = f2(f2(x));
std::cout << "A b4 = f2(f2(A()));" << std::endl;
A b4 = f2(f2(A()));
std::cout << std::endl;
std::cout << "A a5 = f1(f1(f1(x)));" << std::endl;
A a5 = f1(f1(f1(x)));
std::cout << "A a6 = f1(f1(f1(A())));" << std::endl;
A a6 = f1(f1(f1(A())));
std::cout << "A b5 = f2(f2(f2(x)));" << std::endl;
A b5 = f2(f2(f2(x)));
std::cout << "A b6 = f2(f2(f2(A())));" << std::endl;
A b6 = f2(f2(f2(A())));
}
Which produces the following results:
A a1 = f1(x);
Copy
A a2 = f1(A());
Move
A b1 = f2(x);
Copy
Move
A b2 = f2(A());
Move
A a3 = f1(f1(x));
Copy
Move
A a4 = f1(f1(A()));
Move
A b3 = f2(f2(x));
Copy
Move
Move
A b4 = f2(f2(A()));
Move
Move
A a5 = f1(f1(f1(x)));
Copy
Move
A a6 = f1(f1(f1(A())));
Move
A b5 = f2(f2(f2(x)));
Copy
Move
Move
Move
A b6 = f2(f2(f2(A())));
Move
Move
Move
You might be able to do some template tricks to avoid writing multiple overloads, for example:
template <class T>
param_return_type<T&&>::type f3(T&& y, typename std::enable_if<...>::type* dummy = 0 )
{
typedef return_t param_return_type<T&&>::type;
return_t x = static_cast<return_t>(y);
x.inc();
return static_cast<return_t>(x);
}
Where param_return_type<T>::type is T when passed (const) T&, and T&& when passed T&&. std::enable_if<...> you can use if you only want this template to take particular parameters.
I wasn't sure how to write a definition of param_return_type<T>::type, as it seems there is no std::remove_lvalue_reference. If anyone knows how to, feel free to edit/add to my post.
my_macro << 1 << "hello world" << blah->getValue() << std::endl;
should expand into:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
#define my_macro my_stream()
class my_stream: public std::ostringstream {
public:
my_stream() {}
~my_stream() {
ThreadSafeLogging(this->str());
}
};
int main() {
my_macro << 1 << "hello world" << std::endl;
}
A temporary of type my_stream is created, which is a subclass of ostringstream. All operations to that temporary work as they would on an ostringstream.
When the statement ends (ie. right after the semicolon on the whole printing operation in main()), the temporary object goes out of scope and is destroyed. The my_stream destructor calls ThreadSafeLogging with the data "collected" previously.
Tested (g++).
Thanks/credits to dingo for pointing out how to simplify the whole thing, so I don't need the overloaded operator<<. Too bad upvotes can't be shared.
Couldn't you just derive from ostream and provide your own thread safe implementation? Then you could just do
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
And get the exact same functionality without macros and using C++ properly?
No. The problem is that without using function syntax, a macro is limited to only being replaced where it is.
But if you were willing to use function syntax, you can then replace stuff both before and after the args.
my_macro(1 << "hello world" << blah->getValue() << std::endl);
You could by defining MyMacro as:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
Take a look at google-glog, they do this using a temporary object instanciated with a
LOG(INFO) << "log whatever" << 1;
and they also have other interesting macros such as LOG_IF et al.
Considering you have these lines included somewhere in your code, yes it is possible
#include <iostream>
#include <sstream>
__LINE__ macro is defined by all standart compilers.
So we can use it to generate a variable name wich is different each time you use the macro :)
Here is a new version that is seen as a one-statement instruction only:
(EDITED)
#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
Var(s, __LINE__).x<2; ++Var(s, __LINE__).x) \
if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
else Var(s, __LINE__).oss
// So you can use it like this
int main()
{
if (4 != 2)
my_macro << 4 << " hello " << std::endl;
my_macro << 2 << " world !" << std::endl;
}
Developper probably won't need to use this macro twice on same line becasue of simplicity of operator <<. But in case you need this, you can switch the use of __LINE__ by __COUNTER__ (which is non standard!). Thanks to Quuxplusone for this tip
Here's another nasty trick I saw somewhere else. It has a significant disadvantage compared to my other answer: you can't use it twice in the same scope because it declares a variable. However, it may still be interesting for other cases where you want to have somemacro foo run something after foo.
#define my_macro \
std::ostringstream oss; \
for (int x=0; x<2; ++x) \
if (x==1) ThreadSafeLogging(oss.str()); \
else oss
int main() {
my_macro << 1 << "hello world" << std::endl;
}
The logging setup I have is quite similar:
bool ShouldLog(const char* file, size_t line, Priority prio);
class LoggerOutput : public std::stringstream {
public:
LoggerOutput(const char* file, size_t line, Priority prio)
: prio(prio)
{
Prefix(file, line, prio);
}
void Prefix(const char* file, size_t line, Priority prio);
~LoggerOutput() {
Flush();
}
void Flush();
private:
Priority prio;
};
#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)
If your logging is disabled, the ostream is never created and little overhead exists. You can configure logging on file name & line number(s) or priority levels. The ShouldLog function can change between invocations, so you could throttle or limit output. The log output uses two functions to modify itself, Prefix that adds a "file:line: (PRIO) " prefix to the line, and Flush() which both flushes it to the log output as a single command and adds a newline to it. In my implementation it always does, but you can make that conditional if one is not already there.