While trying to write a class that times the duration between calling it's constructor and destructor, I ran into what I think is a bug in clang. (Edit: it's not a bug; it's implementation defined copy elision)
The timer
struct below keeps a pointer to the duration object that's passed in as reference and adds the duration of the scope to this.
#include <iostream>
#include <chrono>
struct timer {
using clock = std::chrono::high_resolution_clock;
using time_point = clock::time_point;
using duration = clock::duration;
duration* d_;
time_point start_;
timer(duration &d) : d_(&d), start_(clock::now()) {}
~timer(){
auto duration = clock::now() - start_;
*d_ += duration;
std::cerr << "duration: " << duration.count() << std::endl;
}
};
timer::duration f(){
timer::duration d{};
timer _(d);
std::cerr << "some heavy calculation here" << std::endl;
return d;
}
int main(){
std::cout << "function: " << f().count() << std::endl;
}
When compiling this with clang 7.0.0, the output is:
some heavy calculation here
duration: 21642
function: 21642
while for g++ 8 the output is
some heavy calculation here
duration: 89747
function: 0
In this case I do like clangs behavior, but from what I've found elsewhere the return value is supposed to be copied before destructors are run.
Is this a bug with Clang? Or does this depend on (implementation defined?) return value optimization?
The behavior is the same independent of whether the duration d
in timer
is a pointer or a reference.
--
I do realise that the compiler inconsistency can be solved by changing f
so that the scope of the timer ends before the return, but that's beside the point here.
timer::duration f(){
timer::duration d{};
{
timer _(d);
std::cerr << "some heavy calculation here" << std::endl;
}
return d;
}
Short answer: due to NRVO, the output of the program may be either 0
or the actual duration. Both are valid.
For background, see first:
Guideline:
For example, when we see the following pattern:
T f() {
T ret;
A a(ret); // or similar
return ret;
}
We need to ask ourselves: does A::~A()
modify our return value somehow? If yes, then our program most likely has a bug.
For example:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With