連続キャッシュの例

「連続キャッシュ」の例では、QContiguousCache を使用して、非常に大規模なモデルのメモリ使用量を管理する方法を示しています。 環境によってはメモリに制限があるほか、制限がない場合でも、アプリケーションが過度にメモリを消費することはユーザーにとって好ましくありません。リスト全体をメモリに読み込むのではなく、QContiguousCache を使用してリストを管理することで、アクセスするデータセットのサイズにかかわらず、アプリケーションが使用するメモリ量を制限することができます。

QContiguousCache を使用する最も簡単な方法は、アイテムが要求されるたびにキャッシュすることです。ビューが N 行目のアイテムを要求する場合、N 行付近のアイテムも同時に要求される可能性が高いからです。

QVariant RandomListModel::data(constQModelIndex&index, introle)const
{
    if(role!=Qt::DisplayRole)
        returnQVariant();

    introw=index.row();

    if(row>m_rows.lastIndex()) {
        if(row-m_rows.lastIndex()>lookAhead)
            cacheRows(row-halfLookAhead, qMin(m_count,row+halfLookAhead));
        else while(row>m_rows.lastIndex())
                m_rows.append(fetchRow(m_rows.lastIndex()+ 1));
    }else if(row<m_rows.firstIndex()) {
        if(m_rows.firstIndex()-row>lookAhead)
            cacheRows(qMax(0, row - halfLookAhead), row + halfLookAhead);
       else while(row<m_rows.firstIndex())
                m_rows.prepend(fetchRow(m_rows.firstIndex()- 1));
    }

    returnm_rows.at(row);
}

voidRandomListModel::cacheRows(intfrom, intto)const
{
    for(inti=from; i<=to;++i)
        m_rows.insert(i,fetchRow(i));
}

行を取得した後、このクラスはその行が連続キャッシュの現在の範囲内にあるかどうかを判定します。代わりに、単に以下のコードを記述しても同様に有効でした。

while (row > m_rows.lastIndex())
    m_rows.append(fetchWord(m_rows.lastIndex()+1);
while (row < m_rows.firstIndex())
    m_rows.prepend(fetchWord(m_rows.firstIndex()-1);

しかし、スクロールバーを直接使用するとリストが行を飛び越えることが多いため、上記のコードでは、古い行と新しい行の間のすべての行が取得されてしまうことになります。

QContiguousCache::lastIndex() およびQContiguousCache::firstIndex() を使用することで、この例ではキャッシュが現在リストのどの部分をキャッシュしているかを特定できます。これらの値は、キャッシュ自身のメモリ内のインデックスを表すものではなく、キャッシュが表す仮想的な無限配列を表しています。

QContiguousCache::append() およびQContiguousCache::prepend() を使用することで、要求された行が現在のキャッシュ範囲からそれほど離れていない場合、画面上にまだ表示されている可能性のある項目が失われることを防ぎます。QContiguousCache::insert() は、QContiguousCache がギャップを許容しないため、キャッシュから複数の項目を削除してしまう可能性があります。 キャッシュ内で、行間に大きなギャップがある行間を素早く行き来する必要がある場合は、代わりに `QCache ` の使用を検討してください。

以上です。非常に大規模なリストに対して最小限のメモリしか使用しない、極めて合理的なキャッシュです。この例では、単語をキャッシュに格納するためのアクセサは、固定された情報ではなくランダムな情報を生成します。これにより、サンプルを実行した際に、キャッシュ範囲が局所的な行数に対してどのように維持されているかを確認できます。

QString RandomListModel::fetchRow(int position) const
{
    return QString::number(QRandomGenerator::global()->bounded(++position));
}

また、アプリケーションのペイントルーチン以外で、アイテムをキャッシュにプリフェッチすることも検討する価値があります。これは、別のスレッドを使用するか、QTimer を使用して、現在のキャッシュ範囲外の行が要求される前に、キャッシュの範囲を段階的に拡張することで実現できます。

サンプルプロジェクト @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.