web-dev-qa-db-ja.com

C ++ std :: chrono :: time_pointをlongとbackに変換する方法

std::chrono::time_pointlong型(整数64ビット)との間で変換する必要があります。 std::chronoの使用を開始しています...

ここに私のコードがあります:

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;
}

このコードはコンパイルされますが、成功を示しません。

最後にdtnowと異なるのはなぜですか?

そのコードには何が欠けていますか?

59
Mendes
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_mstime_pointに基づくsystem_clockですが、system_clockの精度ではなく、millisecondsの精度を持ちます。

auto Epoch = now_ms.time_since_Epoch();

Epochのタイプはstd::chrono::millisecondsになりました。そして、この次のステートメントは本質的にノーオペレーションになります(単にコピーを作成し、変換を行いません):

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(Epoch);

ここに:

long duration = value.count();

あなたと私のコードの両方で、durationsystem_clockのエポック以降のmillisecondsの数を保持します。

この:

std::chrono::duration<long> dur(duration);

duration、およびlongの精度で表されるsecondsを作成します。これは、実質的にreinterpret_casts millisecondsvalueから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)

dtmillisecondsの整数を保持しますが、nowmillisecondよりも細かいティックの整数を保持するため(例: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に戻る途中でtime_pointmillisecondsとして解釈するnotです。そのリスクを軽減する1つの可能な方法は、次のように書くことです。

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

これにより、sys_millisecondsを使用して帰路と帰路の2か所で使用するだけで、リスクが軽減されます。

そしてもう一つの例:system_clockがサポートする期間(マイクロ秒、10th マイクロ秒またはナノ秒)。その後、上記のようにミリ秒を指定することを心配する必要はありません。コードは次のように単純化されます。

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;
}

これは機能しますが、一方のプラットフォームで半分の変換(積分への変換)を実行し、別のプラットフォームで残りの半分(積分からの変換)を実行すると、2つの変換に対してsystem_clock::durationの精度が異なるというリスクが発生します。

128
Howard Hinnant

また、その時点でミリ秒数を取得する方法は2つあります。どちらが優れているかはわかりませんが、それらをベンチマークしましたが、どちらも同じパフォーマンスを持っているので、好みの問題だと思います。おそらく、ハワードは次のようにチャイムを鳴らすことができました。

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();

最初のものは、私の心の中で左から右に向かってよりはっきりと読みます。

2
Feem

time_pointオブジェクト は、他のtime_pointまたはdurationオブジェクトとの算術演算のみをサポートします。

longを指定された単位の duration に変換する必要があります。そうすれば、コードは正しく機能するはずです。

0
Mr. Llama

単一行として:

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();
0
Harald P.