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 millisecondpräzise verkehren möchten , ist es gut, in den time_pointfolgenden Schritten zu verdecken :
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_msist ein time_point, basierend auf system_clock, aber mit der Präzision von millisecondsanstelle der Präzision, die Sie system_clockhaben.
auto epoch = now_ms.time_since_epoch();
epochhat 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 durationdie Nummer millisecondsseit der Epoche von system_clock.
Dies:
std::chrono::duration<long> dur(duration);
Erstellt eine durationDarstellung mit a longund einer Genauigkeit von seconds. Dies ist effektiv reinterpret_castdas millisecondsFesthalten valuean 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_pointbasierend auf system_clock, mit der Fähigkeit, eine Genauigkeit auf der system_clocknativen 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 dteine ganzzahlige Anzahl von milliseconds, aber noweine ganzzahlige Anzahl von Zecken feiner als a millisecond(zB microsecondsoder nanoseconds) enthält. Somit würde der Test nur bei der seltenen Chance, dass system_clock::now()eine ganzzahlige Anzahl von zurückgegeben millisecondswird, 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::chronoausfü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_pointund 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_durationwie millisecondsauf 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_millisecondsauf 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_clockStü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::durationdie beiden Konvertierungen unterschiedliche Präzisionen haben.
std::chrono::duration<long,std::milli> durund selbst dann können Rundungsfehler auftreten (std::chrono::system_clockhat wahrscheinlich eine höhere Auflösung als Millisekunden).