Qtの時間計測QElapsedTimer::elapsed()の代替手段を比較!最適な選び方

2025-05-27

QElapsedTimer クラスは、時間の経過を正確に測定するためのQtのクラスです。qint64 QElapsedTimer::elapsed() メソッドは、このタイマーが最後に開始された(start() または restart() が呼ばれた)時点から現在までの経過時間をミリ秒単位で返します。

戻り値の型について

  • qint64 は、Qtで定義されている64ビット符号付き整数型です。これにより、非常に長い時間(数億年分)をミリ秒単位で表現できます。

主な特徴と用途

  1. 経過時間の測定
    最も基本的な使い方は、ある処理にかかった時間を測定することです。

    #include <QElapsedTimer>
    #include <QDebug>
    
    void mySlowOperation() {
        // 時間のかかる処理...
        for (int i = 0; i < 1000000; ++i) {
            volatile int x = i * i; // 何らかの計算
        }
    }
    
    int main() {
        QElapsedTimer timer;
        timer.start(); // タイマーを開始
    
        mySlowOperation(); // 測定したい処理を実行
    
        qint64 elapsedMs = timer.elapsed(); // 経過時間を取得
        qDebug() << "処理にかかった時間:" << elapsedMs << "ミリ秒";
    
        return 0;
    }
    
  2. モノトニッククロックの使用
    QElapsedTimer は可能な限りモノトニッククロック(単調増加するクロック)を使用しようとします。これは、システムの時刻変更(手動での時刻修正やサマータイムの切り替えなど)に影響されないという利点があります。そのため、QTime のように人間が読める時刻(例:Unixエポックからのミリ秒)に変換することはできませんが、正確な時間間隔の測定に適しています。

  3. パフォーマンス測定やデバッグ
    プログラムの特定の部分のパフォーマンスを測定したり、デバッグのために処理時間を把握したりするのに非常に役立ちます。

  4. タイムアウト処理
    QElapsedTimer::hasExpired(qint64 timeout) と組み合わせて、特定の時間内に処理が完了したかどうかを判定するタイムアウト処理にも利用できます。

    #include <QElapsedTimer>
    #include <QDebug>
    #include <QThread> // QThread::msleep のために必要
    
    void performLimitedTimeOperation(int maxTimeMs) {
        QElapsedTimer timer;
        timer.start();
    
        while (!timer.hasExpired(maxTimeMs)) {
            qDebug() << "処理中...";
            QThread::msleep(50); // 少し待機
            if (timer.elapsed() > maxTimeMs / 2) {
                // 途中で条件を満たした場合などにループを抜ける
                // break;
            }
        }
        qDebug() << "処理完了(またはタイムアウト)。経過時間:" << timer.elapsed() << "ミリ秒";
    }
    
    int main() {
        performLimitedTimeOperation(500); // 500ミリ秒でタイムアウトする処理
        return 0;
    }
    

注意点

  • QElapsedTimer は「ストップ」という概念を持ちません。elapsed() を呼び出すたびに、最後に start() または restart() が呼ばれてからの経過時間が計算されて返されます。時間をリセットして再測定したい場合は restart() を使用します。restart() はタイマーを再開し、かつ前回の開始からの経過時間を返します。
  • start() を呼び出す前に elapsed() を呼び出すと、未定義の動作になる可能性があります。必ず start() でタイマーを開始してから elapsed() を使用してください。


QElapsedTimer は時間の計測に非常に便利ですが、その性質上、いくつか注意すべき点があります。

start() の呼び出し忘れまたは不正なタイミングでの呼び出し

エラーの症状

  • プログラムがクラッシュする(未定義動作)。
  • 期待とは異なる、非常に大きな(ランダムな)値を返す。
  • elapsed() が常に0を返す、または非常に小さな値しか返さない。

原因
QElapsedTimer::elapsed() は、タイマーが最後に start() または restart() によって開始された時点からの経過時間を返します。start() が一度も呼ばれていないか、elapsed() が呼ばれるよりも後で start() が呼ばれている場合、正しい計測結果は得られません。QElapsedTimerstart() を呼び出すまでは無効な状態です。無効なタイマーで elapsed() を呼び出すと未定義動作になります。

トラブルシューティング

  • restart() の使用を検討する。 複数の計測を連続して行いたい場合、elapsed() で時間を取得してから start() を呼び出す代わりに、restart() を使うと、前回の開始からの経過時間を返しつつ、同時にタイマーをリセットして再開できます。これはより効率的で、間違いも起こりにくいです。

    QElapsedTimer timer;
    timer.start(); // 最初の計測開始
    
    // 処理A
    
    qint64 elapsedA = timer.elapsed(); // 処理Aの時間を取得
    qDebug() << "処理Aの時間:" << elapsedA << "ミリ秒";
    
    // 処理B (Aの計測が終わった後、続けてBの計測を開始)
    // ここで timer.start() を再度呼び出すのではなく、restart() を使うと便利
    qint64 elapsedSinceLastStart = timer.restart(); // タイマーをリセットしつつ、Aの時間を再度取得 (この場合はelapsedAと同じになるはず)
    
    // 処理B
    
    qint64 elapsedB = timer.elapsed(); // 処理Bの時間を取得
    qDebug() << "処理Bの時間:" << elapsedB << "ミリ秒";
    
  • isValid() でタイマーの状態を確認する。 デバッグ時に if (!timer.isValid()) { qDebug() << "Timer is not valid!"; } のようにチェックすることで、タイマーが開始されていないことを早期に発見できます。

  • start() が正しく呼び出されているか確認する。 処理の計測を開始したい直前に timer.start(); を記述しているか確認してください。

解像度と精度に関する誤解

エラーの症状

  • 非常に短い間隔で elapsed() をポーリングすると、同じ値が連続して返され、その後急に大きな値にジャンプする。
  • 短い時間(例:1ミリ秒未満)の処理を計測しても、常に0ミリ秒や特定の最小単位(例:16ミリ秒)の倍数しか返さない。

原因
QElapsedTimer は可能な限り高精度なシステムクロックを利用しようとしますが、実際のタイマーの解像度(分解能)はオペレーティングシステムやハードウェアに依存します。 特にWindowsシステムでは、デフォルトのシステムタイマーの解像度が10ミリ秒から16ミリ秒程度である場合があります。これは、QElapsedTimer::nsecsElapsed() がナノ秒単位を返すとしても、実際にナノ秒レベルの精度があるわけではないことを意味します。

トラブルシューティング

  • 短い間隔でのポーリングを避ける。 非常に短い間隔で elapsed() を繰り返し呼び出しても、タイマーの解像度より短い時間では値が変化しないことがあります。これはエラーではなく、単にシステムのタイマーの制約によるものです。
  • タイマーの解像度を理解する。 非常に短い時間(数ミリ秒以下)の正確な計測が必要な場合は、QElapsedTimer の精度に限界があることを認識してください。マイクロ秒やナノ秒単位の精度が本当に必要な場合は、プラットフォーム固有のより低レベルなAPI(Windowsの QueryPerformanceCounter やLinuxの clock_gettime with CLOCK_MONOTONIC_RAW など)を検討する必要があるかもしれません。ただし、Qtはこれらの違いを抽象化しようとします。

マルチスレッド環境での注意点

エラーの症状

  • 複数のスレッドで同じ QElapsedTimer オブジェクトを使用すると、計測値が不安定になったり、競合状態が発生したりする。

原因
QElapsedTimer はスレッドセーフではありません。同じ QElapsedTimer オブジェクトを複数のスレッドから同時に変更(start()restart() を呼び出す)したり、elapsed() を呼び出したりすると、競合状態が発生し、予期しない結果やクラッシュにつながる可能性があります。

トラブルシューティング

  • 共有する場合はロック(ミューテックス)を使用する。 どうしても一つの QElapsedTimer オブジェクトを複数のスレッドで共有する必要がある場合は、QMutex などのロック機構を使用して、QElapsedTimer のメソッド呼び出しを保護する必要があります。しかし、パフォーマンス上のオーバーヘッドが生じるため、可能な限り各スレッドで独自のタイマーを使用することをお勧めします。

    #include <QElapsedTimer>
    #include <QMutex>
    #include <QDebug>
    #include <QThread>
    
    QElapsedTimer sharedTimer;
    QMutex timerMutex;
    
    void someThreadFunction() {
        QMutexLocker locker(&timerMutex); // ロックを取得
        if (!sharedTimer.isValid()) {
            sharedTimer.start();
        }
        qDebug() << "経過時間(スレッド内):" << sharedTimer.elapsed() << "ミリ秒";
        // lockerのスコープを抜けるときにロックが解放される
    }
    
  • 各スレッドで独自の QElapsedTimer オブジェクトを使用する。 これが最も推奨される方法です。各スレッドが必要な時に独立したタイマーを保持することで、スレッド間の干渉を避けることができます。

システム時刻の変更による影響 (QElapsedTimer の特性として)

エラーの症状

  • 稀に、計測値が大きく飛んだり、負の値になったりする(通常、QElapsedTimerではこれは発生しにくいですが、古いQtバージョンや特定のOSの組み合わせで報告されたケースがある)。

原因
QElapsedTimer は、可能な限りモノトニッククロック(単調増加するクロック)を使用します。これにより、ユーザーがシステムの時刻を変更したり、サマータイムが切り替わったりしても、計測結果が影響を受けないように設計されています。そのため、通常 QTime などで起こりうるシステム時刻変更による影響は受けにくいです。 ただし、非常に古いOSや特定の構成では、完全にモノトニックなクロックが利用できない場合があり、その場合にまれに問題が発生する可能性もゼロではありません。

トラブルシューティング

  • デバッグ目的でシステム時刻の影響を受けるかどうか確認したい場合は、QElapsedTimer::isMonotonic() を使用して、現在のシステムでモノトニッククロックが使用されているか確認できます。
  • ほとんどの場合、QElapsedTimer を使用していればこの問題は意識する必要がありません。もし異常な値を確認した場合は、QtのバージョンとOSの組み合わせを確認し、既知のバグがないかQtのバグトラッカーやフォーラムを検索してみる価値はあります。


QElapsedTimer は、主に処理時間の測定や、特定の時間内でのループ実行、タイムアウト処理などに用いられます。

基本的な処理時間の測定

ある関数やコードブロックの実行にかかった時間を測定する最も一般的な例です。

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread> // QThread::msleep のために必要

// 時間のかかるダミーの処理
void performHeavyCalculation() {
    qDebug() << "計算を開始します...";
    // 実際にはもっと複雑な処理が入る
    QThread::msleep(1500); // 1.5秒間スリープ
    qDebug() << "計算が終了しました。";
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QElapsedTimer timer; // QElapsedTimer オブジェクトを作成

    // タイマーを開始
    timer.start();

    // 測定したい処理を実行
    performHeavyCalculation();

    // 経過時間を取得(ミリ秒単位)
    qint64 elapsedMs = timer.elapsed();

    qDebug() << "処理にかかった時間:" << elapsedMs << "ミリ秒";

    return 0; // 例なのでアプリケーションを終了
}

説明

  1. QElapsedTimer timer; でタイマーオブジェクトを宣言します。
  2. timer.start(); でタイマーをスタートさせます。ここから時間計測が始まります。
  3. performHeavyCalculation(); のように、時間を計測したい処理を呼び出します。
  4. qint64 elapsedMs = timer.elapsed(); で、start() が最後に呼ばれてからの経過時間をミリ秒単位で取得します。

restart() を使った連続的な時間測定

複数の連続する処理の時間をそれぞれ測定したい場合、restart() を使うと便利です。restart() は、経過時間を返すと同時にタイマーをリセットして再開します。

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread>

void step1() {
    qDebug() << "ステップ1を実行中...";
    QThread::msleep(500); // 0.5秒スリープ
}

void step2() {
    qDebug() << "ステップ2を実行中...";
    QThread::msleep(800); // 0.8秒スリープ
}

void step3() {
    qDebug() << "ステップ3を実行中...";
    QThread::msleep(300); // 0.3秒スリープ
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QElapsedTimer timer;
    timer.start(); // 全体の計測を開始

    qDebug() << "---------------------------------";

    step1();
    // step1 の経過時間を取得し、同時にタイマーを再開
    qint64 elapsedStep1 = timer.restart();
    qDebug() << "ステップ1の処理時間:" << elapsedStep1 << "ミリ秒";

    qDebug() << "---------------------------------";

    step2();
    // step2 の経過時間を取得し、同時にタイマーを再開
    qint64 elapsedStep2 = timer.restart();
    qDebug() << "ステップ2の処理時間:" << elapsedStep2 << "ミリ秒";

    qDebug() << "---------------------------------";

    step3();
    // step3 の経過時間を取得(ここではタイマーを再開する必要はない)
    qint64 elapsedStep3 = timer.elapsed();
    qDebug() << "ステップ3の処理時間:" << elapsedStep3 << "ミリ秒";

    qDebug() << "---------------------------------";

    // 全体の経過時間は、各ステップの経過時間を合計するか、
    // 最初の start() から最後に elapsed() を呼ぶことで計算可能
    // ただし、上記コードでは timer.restart() を使っているため、
    // step3 の後の timer.elapsed() は step3 の時間のみを返します。
    // 全体の時間を測るには、最初の start() の値を別途保持しておくか、
    // 最後の restart() を呼び出す前に elapsed() を使います。
    // ここでは、各ステップの合計で全体の時間を見積もります。
    qDebug() << "全体の合計処理時間 (概算):" << (elapsedStep1 + elapsedStep2 + elapsedStep3) << "ミリ秒";


    return 0;
}

説明

  • timer.restart() は、前回の start() または restart() からの経過時間を返すと同時に、タイマーを新しい計測のためにリセットします。これにより、コードが簡潔になります。

hasExpired() を使ったタイムアウト処理や時間制限付きループ

特定の時間内に処理を完了させたい場合や、時間制限のあるループを実装する場合に hasExpired() が便利です。

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread>

// 指定された時間まで処理を実行する関数
void processUntilTimeout(qint64 maxTimeMs) {
    QElapsedTimer timer;
    timer.start();

    qDebug() << "最大" << maxTimeMs << "ミリ秒で処理を実行します...";

    int counter = 0;
    // タイマーがタイムアウトするまでループを続ける
    while (!timer.hasExpired(maxTimeMs)) {
        // ここに実行したい処理を入れる
        qDebug() << "処理中... 経過時間:" << timer.elapsed() << "ミリ秒";
        QThread::msleep(100); // 少し待機
        counter++;
        if (counter > 20) { // 無限ループ防止のための安全装置
            qDebug() << "最大反復回数に達しました。";
            break;
        }
    }

    qDebug() << "処理が終了しました。最終的な経過時間:" << timer.elapsed() << "ミリ秒";
    if (timer.elapsed() >= maxTimeMs) {
        qDebug() << "タイムアウトしました。";
    } else {
        qDebug() << "時間内に処理が完了しました。";
    }
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    processUntilTimeout(500); // 500ミリ秒の制限
    qDebug() << "\n別の制限時間で試行します。";
    processUntilTimeout(1200); // 1200ミリ秒の制限

    return 0;
}

説明

  • この例では、ループ内でポーリングを行い、時間が経過したかどうかを定期的にチェックしています。
  • timer.hasExpired(maxTimeMs) は、start() が最後に呼ばれてから maxTimeMs ミリ秒以上経過していれば true を返します。

nsecsElapsed() を使ったナノ秒単位の計測(高精度な場合)

QElapsedTimer は、可能な限りシステムで利用可能な最も高精度なモノトニッククロックを使用しようとします。nsecsElapsed() はナノ秒単位の値を返しますが、これは必ずしもナノ秒の精度があることを保証するものではなく、システムによってはミリ秒単位の解像度で内部的にナノ秒に変換されている場合もあります。しかし、より高精度な計測が必要な場合に利用を検討できます。

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>

void performVeryShortOperation() {
    // 非常に短い処理
    volatile int sum = 0;
    for (int i = 0; i < 100000; ++i) {
        sum += i;
    }
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QElapsedTimer timer;
    timer.start();

    performVeryShortOperation();

    // ナノ秒単位で経過時間を取得
    qint64 elapsedNsecs = timer.nsecsElapsed();

    qDebug() << "非常に短い処理にかかった時間:" << elapsedNsecs << "ナノ秒";
    qDebug() << "(約 " << (double)elapsedNsecs / 1000000.0 << "ミリ秒)";

    return 0;
}
  • timer.nsecsElapsed() は、start() が最後に呼ばれてからの経過時間をナノ秒単位で返します。ただし、前述の通り、実際の精度はOSやハードウェアに依存します。


QTime クラス (QTime::elapsed())

QElapsedTimer が導入される前は、QTime が時間の計測によく使われていました。QTime::elapsed() もミリ秒単位で経過時間を返します。

特徴

  • 用途
    主にUIに表示する経過時間や、時刻に基づくログ記録など、人間が読みやすい時刻が必要な場合に有用です。パフォーマンス測定には通常 QElapsedTimer が推奨されます。
  • モノトニックではない
    QTime はシステム時刻に依存するため、ユーザーがシステムの時刻を変更したり、サマータイムが切り替わったりすると、計測結果が影響を受ける可能性があります。そのため、厳密な時間間隔の測定には適していません。
  • 人間が読める時刻に基づいている
    QTime は日中の時刻(時、分、秒、ミリ秒)を表すのに適しており、Unixエポック(1970年1月1日00:00:00 UTC)からのミリ秒として時間情報を保持します。

使用例

#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include <QThread>

void performSomeOperation() {
    qDebug() << "何らかの処理を開始します...";
    QThread::msleep(1200); // 1.2秒スリープ
    qDebug() << "処理が終了しました。";
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QTime time; // QTime オブジェクトを作成

    time.start(); // タイマーを開始

    performSomeOperation();

    qint64 elapsedMs = time.elapsed(); // 経過時間を取得
    qDebug() << "QTimeによる処理時間:" << elapsedMs << "ミリ秒";

    return 0;
}

QDeadlineTimer クラス

Qt 5.10 以降で導入された QDeadlineTimer は、主に未来の特定の時刻までの残り時間を計算したり、処理がタイムアウトしたかどうかを判定したりするのに特化したクラスです。QElapsedTimer と同様に、可能な限りモノトニッククロックを使用します。

特徴

  • 用途
    ネットワーク通信のタイムアウト、時間制限のあるユーザー入力待ち、ゲームループにおけるフレーム時間管理など、特定の期限を設けて処理を進める場合に非常に適しています。
  • QElapsedTimer と逆の概念
    QElapsedTimer が「どれだけ時間が経過したか」を測るのに対し、QDeadlineTimer は「あとどれだけ時間が残っているか」を管理します。
  • タイムアウト判定に特化
    hasExpired() メソッドが主な用途であり、「あとどれくらい時間があるか」「タイムアウトしたか」を判定するのに非常に便利です。

使用例

#include <QCoreApplication>
#include <QDeadlineTimer>
#include <QDebug>
#include <QThread>

void processWithDeadline(qint64 timeoutMs) {
    QDeadlineTimer deadline(timeoutMs); // タイムアウト時間を設定 (相対時間)

    qDebug() << "期限: " << timeoutMs << "ミリ秒以内";

    while (!deadline.hasExpired()) { // 期限が過ぎるまでループ
        qDebug() << "処理中... 残り時間:" << deadline.remainingTime() << "ミリ秒";
        QThread::msleep(100); // 少し待機

        // 何らかの条件で早期終了することも可能
        // if (someConditionMet) {
        //     break;
        // }
    }

    if (deadline.hasExpired()) {
        qDebug() << "処理がタイムアウトしました。";
    } else {
        qDebug() << "処理が期限内に完了しました。";
    }
    qDebug() << "最終的な経過時間:" << (timeoutMs - deadline.remainingTime()) << "ミリ秒";
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    processWithDeadline(800); // 800ミリ秒の期限
    qDebug() << "\n-----------------\n";
    processWithDeadline(2000); // 2000ミリ秒の期限

    return 0;
}

C++ 標準ライブラリのクロック (<chrono>)

C++11 以降の標準ライブラリには、時間に関する強力な機能を提供する <chrono> ヘッダーが含まれています。これはプラットフォームに依存しない、非常に汎用的な代替手段となります。

特徴

  • 高い柔軟性
    時間単位(ナノ秒、マイクロ秒、ミリ秒、秒など)を細かく指定でき、期間の計算や変換が容易です。
  • 多様なクロック
    std::chrono::system_clock (システム時刻、非モノトニック) や std::chrono::steady_clock (モノトニッククロック) など、複数のクロックタイプが提供されます。QElapsedTimer の代替としては std::chrono::steady_clock が最も適切です。
  • 標準化
    C++ の標準機能であるため、Qtに依存せず、他のC++プロジェクトにも簡単に移植できます。

使用例 (std::chrono::steady_clock)

#include <iostream>
#include <chrono> // C++標準ライブラリの時間機能
#include <thread> // std::this_thread::sleep_for のために必要

void performLongTask() {
    std::cout << "長いタスクを実行中..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1800)); // 1.8秒スリープ
    std::cout << "長いタスクが完了しました。" << std::endl;
}

int main() {
    // steady_clock を使用して開始時刻を記録
    auto start_time = std::chrono::steady_clock::now();

    performLongTask();

    // 終了時刻を記録
    auto end_time = std::chrono::steady_clock::now();

    // 期間を計算 (duration オブジェクト)
    auto duration = end_time - start_time;

    // ミリ秒単位に変換して出力
    long long elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
    std::cout << "std::chrono::steady_clock による処理時間:" << elapsed_ms << "ミリ秒" << std::endl;

    // ナノ秒単位に変換して出力
    long long elapsed_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
    std::cout << "std::chrono::steady_clock による処理時間:" << elapsed_ns << "ナノ秒" << std::endl;

    return 0;
}

説明

  • std::chrono::duration_cast を使って、その期間を任意の時間単位(例: std::chrono::milliseconds)に変換し、.count() で数値を取得します。
  • 2つの time_point の差を取ることで、期間 (duration) を計算できます。
  • std::chrono::steady_clock::now() は、モノトニックな時間点 (time_point) を返します。

オペレーティングシステム固有のAPI

非常に特殊な要件(例:極めて高い精度、OSの特定機能への依存)がある場合、Qtや標準C++のラッパーを使わずに、直接OSのAPIを呼び出す方法もあります。


  • Linux/macOS (POSIX)
    clock_gettime(CLOCK_MONOTONIC, ...)gettimeofday (一部システムでは非推奨) などがあります。
  • Windows
    QueryPerformanceCounterQueryPerformanceFrequency を組み合わせることで、高分解能なパフォーマンスカウンターを利用できます。

特徴

  • 複雑さ
    APIの利用方法が複雑で、エラーハンドリングやオーバーフロー対策などを自前で行う必要があります。
  • 移植性がない
    コードが特定のOSに強く依存するため、他のプラットフォームに移植する際には大幅な変更が必要になります。
  • 最高レベルの制御と精度(場合による)
    OSが提供する最も低レベルな時間計測機能を利用できます。
  • ゲームエンジンやリアルタイムシミュレーションなど、ミリ秒以下の非常に厳密な時間制御が求められる場合に検討されますが、通常は QElapsedTimer<chrono> で十分です。
代替方法特徴主な用途推奨度
QElapsedTimerモノトニックで高精度、Qtで時間計測の標準。システム時刻変更に影響されない。処理時間計測、パフォーマンス測定、時間制限付きループほとんどのQtアプリケーションで推奨される
QTimeシステム時刻に依存(非モノトニック)。人間が読みやすい時刻。UIでの時刻表示、時刻に基づくログ記録厳密な時間計測には不向き。QElapsedTimer がない古いQtバージョンでは代替として使われた。
QDeadlineTimerモノトニック。未来の期限までの残り時間を管理。hasExpired() でタイムアウト判定が容易。タイムアウト処理、時間制限のあるイベントループ期限管理が必要な場合に非常に便利。QElapsedTimer とは目的が異なるため、適材適所。
std::chrono::steady_clockC++標準ライブラリ(Qt非依存)。モノトニック。多様な時間単位に変換可能。Qtに依存しない汎用的な時間計測、クロスプラットフォームなライブラリ開発Qt環境外のC++コードや、より標準C++に準拠したい場合に有効。機能的にはQElapsedTimerに非常に近い。
OS固有API最高レベルの精度と制御。OSに強く依存し、移植性がない。実装が複雑。極めて厳密なリアルタイム制御、低レイヤー開発ほとんどのケースでは不要。Qtや標準C++の抽象化された機能で十分。特別な理由がない限り避けるべき。