The following code seems to overflow. Why?
#include <chrono>
#include <iostream>
int main() {
auto now = std::chrono::steady_clock::now();
auto low = std::chrono::steady_clock::time_point::min();
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - low).count();
std::cout << elapsed << "\n";
return 0;
}
I would expect low
to be the earliest time point. That's how I understand the "Return value" description under https://en.cppreference.com/w/cpp/chrono/time_point/min.
So, any other value, e.g. now
, should be greater and the difference now - low
should be a positive duration. Unless it somehow overflows somewhere? Is it a bug (unlikely; all main compilers seem to have this issue)? Is it my misunderstanding of chrono somehwere that is at fault?
How can I fix this?
Context: I have a list of elements. Some elements are actively being used, others have a timestamp which tells when they were last used. Periodically, timestamps are checked if they are too old, and if so elements with those early timestamps are removed from the list.
A user can manually invoke a flush operation. It sets all timestamps that exist to low
so that when the next check is performed, all those elements are removed.
I can set low
to be now - reasonableBigButNotTooBig
value to make it work, but I thought std::chrono::steady_clock::time_point::min
would be more idiomatic.
std::chrono::steady_clock::time_point::min()
isn't generally zero, usually std::chrono
clocks use a signed 64-bit integer as the representation of the time_point
. low
is therefore likely to be -2^63
ticks, now
is likely a positive number of ticks therefore now - low
, or equivalently now + 2^63
, is likely to overflow.
The epoch of steady_clock
isn't specified but in general all timestamps will be positive (the epoch is generally the boot time of the computer) so you can use std::chrono::steady_clock::time_point{}
as a "minimum" time point instead.
It overflows for the same reason the following test overflows when instantiated with int32_t
:
#include <cstdint>
#include <iostream>
#include <limits>
template <class I>
void
test()
{
I low = std::numeric_limits<std::int32_t>::min();
I now = 2;
std::cout << "low = " << low << '\n';
std::cout << "now = " << now << '\n';
std::cout << "now - low = " << now-low << "\n\n";
}
int
main()
{
test<std::int32_t>();
test<std::int64_t>();
}
Output:
low = -2147483648
now = 2
now - low = -2147483646
low = -2147483648
now = 2
now - low = 2147483650
The test demonstrates that when you subtract the minimum from a positive number, the result is greater than is representable in a given bit width. Only by using a larger bit width can the answer be computed without overflow.
In your example the overflow is happening with 64 bits instead of 32, but the same principle applies.
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