Ответ 1
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
Это отличное место для auto
:
auto now = std::chrono::system_clock::now();
Поскольку вы хотите трафик с точностью millisecond
, было бы неплохо идти вперед и скрывать его в time_point
:
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
- это time_point
, основанный на system_clock
, но с точностью milliseconds
вместо любой точности вашей system_clock
.
auto epoch = now_ms.time_since_epoch();
epoch
теперь имеет тип std::chrono::milliseconds
. И этот следующий оператор становится практически не-op (просто делает копию и не делает преобразования):
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
Здесь:
long duration = value.count();
В вашем и моем коде duration
хранится число milliseconds
с момента <<28 > .
Это:
std::chrono::duration<long> dur(duration);
Создает duration
, представленный long
, и точность seconds
. Это эффективно reinterpret_cast
milliseconds
, содержащееся в value
до seconds
. Это логическая ошибка. Правильный код будет выглядеть так:
std::chrono::milliseconds dur(duration);
Эта строка:
std::chrono::time_point<std::chrono::system_clock> dt(dur);
создает time_point
на основе system_clock
, с возможностью удержания точности с собственной точностью system_clock
(обычно более тонкой, чем миллисекунды). Однако значение времени выполнения будет правильно отражать то, что фиксируется целое число миллисекунд (при условии, что я исправляю тип dur
).
Даже при коррекции этот тест будет (почти всегда) терпеть неудачу:
if (dt != now)
Поскольку dt
содержит целое число milliseconds
, но now
содержит целое число тиков, более тонкое, чем a millisecond
(например, microseconds
или nanoseconds
). Таким образом, только по редкой вероятности, что system_clock::now()
вернул целое число milliseconds
, пройдет тест.
Но вы можете вместо этого:
if (dt != now_ms)
И теперь вы надежно получите ожидаемый результат.
Объединяя все это:
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;
}
Лично я нахожу все std::chrono
слишком многословными, поэтому я бы назвал его как:
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;
}
Что будет надежно выводиться:
Success.
Наконец, я рекомендую исключить временные сокращения, чтобы уменьшить преобразование кода между time_point
и интегральным типом до минимума. Эти преобразования опасны, и тем меньше кода, который вы пишете, манипулируя голым интегральным типом, тем лучше:
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;
}
Основная опасность выше не интерпретирует integral_duration
как milliseconds
на обратном пути к time_point
. Один из возможных способов уменьшить этот риск - написать:
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
Это снижает риск вплоть до того, что вы используете sys_milliseconds
на выходе и в двух местах на обратном пути.
И еще один пример: предположим, что вы хотите преобразовать в интеграл и из него, который представляет любую продолжительность поддержки system_clock
(микросекунды, 10 th микросекунд или наносекунды). Тогда вам не нужно беспокоиться о том, чтобы указать миллисекунды, как указано выше. Код упрощает:
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;
}
Это работает, но если вы выполняете половину преобразования (до целого) на одной платформе, а другую половину (из интегральной) на другой платформе, вы рискуете, что system_clock::duration
будет иметь разные префикс для двух преобразований.