std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
Dies ist ein großartiger Ort für auto
:
auto now = std::chrono::system_clock::now();
Da Sie millisecond
präzise verkehren möchten , ist es gut, in den time_point
folgenden Schritten zu verdecken :
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
ist ein time_point
, basierend auf system_clock
, aber mit der Präzision von milliseconds
anstelle der Präzision, die Sie system_clock
haben.
auto epoch = now_ms.time_since_epoch();
epoch
hat jetzt typ std::chrono::milliseconds
. Und diese nächste Anweisung wird im Wesentlichen zu einem No-Op (erstellt einfach eine Kopie und führt keine Konvertierung durch):
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
Hier:
long duration = value.count();
Enthält sowohl in Ihrem als auch in meinem Code duration
die Nummer milliseconds
seit der Epoche von system_clock
.
Dies:
std::chrono::duration<long> dur(duration);
Erstellt eine duration
Darstellung mit a long
und einer Genauigkeit von seconds
. Dies ist effektiv reinterpret_cast
das milliseconds
Festhalten value
an seconds
. Es ist ein logischer Fehler. Der richtige Code würde folgendermaßen aussehen:
std::chrono::milliseconds dur(duration);
Diese Linie:
std::chrono::time_point<std::chrono::system_clock> dt(dur);
Erstellt eine time_point
basierend auf system_clock
, mit der Fähigkeit, eine Genauigkeit auf der system_clock
nativen Genauigkeit der (normalerweise feiner als Millisekunden) zu halten. Der Laufzeitwert gibt jedoch korrekt wieder, dass eine ganzzahlige Anzahl von Millisekunden gehalten wird (unter der Annahme meiner Korrektur des Typs von dur
).
Trotz der Korrektur schlägt dieser Test (fast immer) fehl:
if (dt != now)
Weil dt
eine ganzzahlige Anzahl von milliseconds
, aber now
eine ganzzahlige Anzahl von Zecken feiner als a millisecond
(zB microseconds
oder nanoseconds
) enthält. Somit würde der Test nur bei der seltenen Chance, dass system_clock::now()
eine ganzzahlige Anzahl von zurückgegeben milliseconds
wird, bestehen.
Aber Sie können stattdessen:
if (dt != now_ms)
Und Sie erhalten jetzt zuverlässig Ihr erwartetes Ergebnis.
Alles zusammen:
int main ()
{
auto now = std::chrono::system_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
auto value = now_ms.time_since_epoch();
long duration = value.count();
std::chrono::milliseconds dur(duration);
std::chrono::time_point<std::chrono::system_clock> dt(dur);
if (dt != now_ms)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Persönlich finde ich das alles sehr std::chrono
ausführlich und würde es so codieren als:
int main ()
{
using namespace std::chrono;
auto now = system_clock::now();
auto now_ms = time_point_cast<milliseconds>(now);
auto value = now_ms.time_since_epoch();
long duration = value.count();
milliseconds dur(duration);
time_point<system_clock> dt(dur);
if (dt != now_ms)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Welches wird zuverlässig ausgeben:
Success.
Schließlich empfehle ich, temporäre Elemente zu entfernen, um die Konvertierung von Code zwischen time_point
und Integraltyp auf ein Minimum zu reduzieren . Diese Konvertierungen sind gefährlich. Je weniger Code Sie schreiben, um den nackten Integraltyp zu manipulieren, desto besser:
int main ()
{
using namespace std::chrono;
auto now = time_point_cast<milliseconds>(system_clock::now());
using sys_milliseconds = decltype(now);
auto integral_duration = now.time_since_epoch().count();
sys_milliseconds dt{milliseconds{integral_duration}};
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Die Hauptgefahr oben ist nicht das Dolmetschen integral_duration
wie milliseconds
auf dem Weg zurück zu a time_point
. Eine Möglichkeit, dieses Risiko zu mindern, besteht darin, Folgendes zu schreiben:
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
Dies reduziert das Risiko, indem Sie nur sicherstellen, dass Sie es sys_milliseconds
auf dem Weg nach draußen und an den beiden Stellen auf dem Weg zurück verwenden.
Und noch ein Beispiel: Angenommen, Sie zu und von einem integrierten konvertieren wollen , das unabhängig von Dauer repräsentiert system_clock
Stützen (Mikrosekunden, 10 th von Mikrosekunden oder Nanosekunden). Dann müssen Sie sich nicht mehr um die Angabe von Millisekunden wie oben kümmern. Der Code vereinfacht sich zu:
int main ()
{
using namespace std::chrono;
auto now = system_clock::now();
auto integral_duration = now.time_since_epoch().count();
system_clock::time_point dt{system_clock::duration{integral_duration}};
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Dies funktioniert, aber wenn Sie die Hälfte der Konvertierung (von in Integral) auf einer Plattform und die andere Hälfte (von Integral) auf einer anderen Plattform ausführen, besteht das Risiko, dass system_clock::duration
die beiden Konvertierungen unterschiedliche Präzisionen haben.
std::chrono::duration<long,std::milli> dur
und selbst dann können Rundungsfehler auftreten (std::chrono::system_clock
hat wahrscheinlich eine höhere Auflösung als Millisekunden).