Ich muss zu std::chrono::time_point
und von einem long
Typ konvertieren (Ganzzahl 64 Bit). Ich fange an mit std::chrono
...
Hier ist mein Code:
int main ()
{
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto epoch = now.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
long duration = value.count();
std::chrono::duration<long> dur(duration);
std::chrono::time_point<std::chrono::system_clock> dt(dur);
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}
Dieser Code wird kompiliert, zeigt jedoch keinen Erfolg.
Warum ist dt
anders als now
am Ende?
Was fehlt in diesem Code?
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).system_clock
(ungefähr 100-mal höher), aber selbst dies ist normalerweise weniger als eine Mikrosekunde.Antworten:
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 dentime_point
folgenden Schritten zu verdecken :auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
ist eintime_point
, basierend aufsystem_clock
, aber mit der Präzision vonmilliseconds
anstelle der Präzision, die Siesystem_clock
haben.auto epoch = now_ms.time_since_epoch();
epoch
hat jetzt typstd::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 Nummermilliseconds
seit der Epoche vonsystem_clock
.Dies:
std::chrono::duration<long> dur(duration);
Erstellt eine
duration
Darstellung mit along
und einer Genauigkeit vonseconds
. Dies ist effektivreinterpret_cast
dasmilliseconds
Festhaltenvalue
anseconds
. 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 aufsystem_clock
, mit der Fähigkeit, eine Genauigkeit auf dersystem_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 vondur
).Trotz der Korrektur schlägt dieser Test (fast immer) fehl:
if (dt != now)
Weil
dt
eine ganzzahlige Anzahl vonmilliseconds
, abernow
eine ganzzahlige Anzahl von Zecken feiner als amillisecond
(zBmicroseconds
odernanoseconds
) enthält. Somit würde der Test nur bei der seltenen Chance, dasssystem_clock::now()
eine ganzzahlige Anzahl von zurückgegebenmilliseconds
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:
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; // Get current time with precision of milliseconds auto now = time_point_cast<milliseconds>(system_clock::now()); // sys_milliseconds is type time_point<system_clock, milliseconds> using sys_milliseconds = decltype(now); // Convert time_point to signed integral type auto integral_duration = now.time_since_epoch().count(); // Convert signed integral type to time_point sys_milliseconds dt{milliseconds{integral_duration}}; // test if (dt != now) std::cout << "Failure." << std::endl; else std::cout << "Success." << std::endl; }
Die Hauptgefahr oben ist nicht das Dolmetschen
integral_duration
wiemilliseconds
auf dem Weg zurück zu atime_point
. Eine Möglichkeit, dieses Risiko zu mindern, besteht darin, Folgendes zu schreiben: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; // Get current time with native precision auto now = system_clock::now(); // Convert time_point to signed integral type auto integral_duration = now.time_since_epoch().count(); // Convert signed integral type to time_point system_clock::time_point dt{system_clock::duration{integral_duration}}; // test 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.quelle
time_point_cast<milliseconds>(now)
in meiner obigen Antwort verwandten verwandt . Nur die Dauer ist Courser :time_point_cast<days>(now)
.Ich würde auch bemerken, dass es zwei Möglichkeiten gibt, die Anzahl der ms zum Zeitpunkt zu ermitteln. Ich bin mir nicht sicher, welches besser ist. Ich habe sie verglichen und beide haben die gleiche Leistung. Ich denke, es ist eine Frage der Präferenz. Vielleicht könnte Howard mitmachen:
auto now = system_clock::now(); //Cast the time point to ms, then get its duration, then get the duration's count. auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count(); //Get the time point's duration, then cast to ms, then get its count. auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();
Der erste liest sich in meinem Kopf deutlicher von links nach rechts.
quelle
als einzelne Zeile:
long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();
quelle
time_point
Objekte unterstützen nur Arithmetik mit anderentime_point
oderduration
Objekten.Sie müssen Ihre
long
in eineduration
der angegebenen Einheiten konvertieren , dann sollte Ihr Code korrekt funktionieren.quelle