O código a seguir parece estar com estouro. Por quê?
#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;
}
Eu esperaria low
que fosse o ponto de tempo mais antigo. É assim que entendo a descrição "Valor de retorno" em https://en.cppreference.com/w/cpp/chrono/time_point/min .
Portanto, qualquer outro valor, por exemplo now
, deve ser maior e a diferença now - low
deve ser uma duração positiva. A menos que, de alguma forma, transborde em algum lugar? É um bug (improvável; todos os principais compiladores parecem ter esse problema )? É algum erro meu de compreensão de chrono que está errado?
Como posso consertar isso?
Contexto: Tenho uma lista de elementos. Alguns elementos estão sendo usados ativamente, outros têm um registro de data e hora que indica quando foram usados pela última vez. Periodicamente, os registros de data e hora são verificados se forem muito antigos e, nesse caso, os elementos com esses registros de data e hora antigos são removidos da lista.
Um usuário pode invocar manualmente uma operação de limpeza. Ela define todos os registros de data e hora existentes para low
que, quando a próxima verificação for realizada, todos esses elementos sejam removidos.
Posso definir low
um now - reasonableBigButNotTooBig
valor para que funcione, mas pensei que std::chrono::steady_clock::time_point::min
seria mais idiomático.
std::chrono::steady_clock::time_point::min()
geralmente não é zero, normalmentestd::chrono
os relógios usam um inteiro de 64 bits com sinal como representação dotime_point
.low
portanto, é provável que seja-2^63
tiques,now
é provável que seja um número positivo de tiques, portantonow - low
, , ou equivalentementenow + 2^63
, é provável que transborde.A época de
steady_clock
não é especificada, mas em geral todos os registros de data e hora serão positivos (a época geralmente é o momento da inicialização do computador), então você pode usá-lastd::chrono::steady_clock::time_point{}
como um ponto de tempo "mínimo".Ele transborda pelo mesmo motivo que o seguinte teste transborda quando instanciado com
int32_t
:Saída:
O teste demonstra que, ao subtrair o mínimo de um número positivo, o resultado é maior do que o representável em uma determinada largura de bits. Somente usando uma largura de bits maior, a resposta pode ser calculada sem estouro.
No seu exemplo, o estouro está acontecendo com 64 bits em vez de 32, mas o mesmo princípio se aplica.