Подкласс c++ qt qabstracttablemodel аварийно завершает работу при обновлении базового qmap

у меня большие проблемы с обновлением пользовательской модели qabstracttable. я хочу иметь табличное представление, которое показывает цены нескольких акций. я получаю цены с локального сервера, который я контролирую. эта установка предназначена для тестирования. информация о ценах получена в рабочем потоке.

я создал подкласс qabstracttablemodel следующим образом:

ЦенаМодель.ч:

class PriceModel : public QAbstractTableModel {
    Q_OBJECT
public:
    PriceModel( QObject* parent = 0 );

    void setPriceMap( const QMap<QString, ITick*> &curTickMap );
    int rowCount( const QModelIndex &parent ) const;
    int columnCount( const QModelIndex &parent ) const;
    QVariant data( const QModelIndex &index, int role ) const;
    QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
private:
    QMap<QString, ITick*> currentTicks;
    QString stockAt( int offset ) const;
};

PriceModel.cpp

#include "PriceModel.h"

PriceModel::PriceModel( QObject* parent ) : QAbstractTableModel( parent ) {
}

int PriceModel::rowCount( const QModelIndex& parent ) const {
    return this->currentTicks.count();
}

int PriceModel::columnCount( const QModelIndex& parent ) const {
    return 4;
}

QString PriceModel::stockAt( int offset ) const {
    return ( currentTicks.begin() + offset ).key();
}

QVariant PriceModel::data( const QModelIndex& index, int role ) const {
    if ( !index.isValid() ) {
        return QVariant();
    }
    if ( role == Qt::TextAlignmentRole ) {
        return int( Qt::AlignRight | Qt::AlignVCenter );
    } else if ( role == Qt::DisplayRole ) {
        QString stock = stockAt( index.row() );
        int i = index.column();
        switch ( i ) {
            case 0 : return currentTicks.value( instrument )->getTime().toString( "hh:mm:ss:zzz" );
            case 1 : return currentTicks.value( instrument )->getBid();
            case 2 : return currentTicks.value( instrument )->getAsk();
            case 3 : return currentTicks.value( instrument )->getBidVolume();
            case 4 : return currentTicks.value( instrument )->getAskVolume();
        }
    }
    return QVariant();
}

QVariant PriceModel::headerData( int section, Qt::Orientation orientation, int role )  const {
    if ( role != Qt::DisplayRole ) {
        return QVariant();
    }
    if ( orientation == Qt::Horizontal ) {
        switch ( section ) {
            case 0 : return QString( "Time" );
            case 1 : return QString( "Bid" );
            case 2 : return QString( "Ask" );
            case 3 : return QString( "Bid Volume" );
            case 4 : return QString( "Ask Volume" );
        }
    } else {
        return instrumentAt( section )->getCurrencyPairWithDelimiter();
    }
    return QVariant();
}

void PriceModel::setTickMap( const QMap<QString,ITick*>& curTickMap ) {
    beginResetModel();
    this->currentTicks = curTickMap;
    endResetModel();
}

модель заполняет табличное представление, когда я вызываю метод setTickMap(qmap‹...>), и все различные акции отображаются так, как ожидалось. (инициализация данных в моей модели работает нормально)

проблема возникает, когда я хочу снова вызвать метод setTickMap(qmap‹...>). приложение аварийно завершает работу, и я не понимаю, почему, и я не получаю серьезного сообщения об ошибке, а именно segvault.

при сбое в конфигурации отладки netbeans открывает вкладку «Разборка» со следующим содержимым:

QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+50: add    %ebx,%r15d
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+85: testb $0x4,0x20(%rax)
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+89: jne 0x7ffff63f4df8 <QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+536>
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+102: add    0x6c(%rsp),%ebx
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+118: mov    %ebx,0x2c(%rsp)
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+106: movq   $0x0,0x40(%rsp)
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+95: mov    0x31c19a(%rip),%rdx        # 0x7ffff6710de0
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+115: mov    (%rdx),%rax
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+122: test   %rax,%rax
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+125: je     0x7ffff63f4c72 <QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+146>
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+127: lea    0x40(%rsp),%rdx
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+132: test   %r13,%r13
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+135: mov    %ebx,%esi
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+137: mov    %r12,%rdi
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+140: cmovne %r13,%rdx
QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+144: callq  *%rax

я засунул назначение карты в методы beginResetModel(), но это, похоже, не работает, так как я просто получаю сбой приложения. как ни странно это работает при первом вызове метода установки. это заставляет меня предположить, что это довольно глупая ошибка. я думаю, поскольку первый вызов работает нормально, мы можем исключить, что это как-то связано с проблемами межпотоковой связи.

эта модель не должна редактироваться пользователем через графический интерфейс, и я знаю, что мог бы использовать табличный виджет только для отображения данных, но я не уверен, будет ли другое представление, которое будет делиться информацией об этой модели. карта с текущими ценами не будет очень большой (максимум 25 предметов), поэтому мне не неудобно сбрасывать модель при каждой новой поступающей цене.

заранее спасибо, и я надеюсь, что кто-то может помочь мне с этим micropor


person MicroPor    schedule 15.01.2012    source источник
comment
Вы уверены, что это компилируется? currentTicks - это QMap<QString, ITick*>, а ваш setTickMap имеет в качестве аргумента QMap<IInstrument*,ITick*>.   -  person pnezis    schedule 16.01.2012
comment
извините, но чтобы упростить проблему, я изменил свой пользовательский интерфейс IInstrument на что-то известное, как qstring...   -  person MicroPor    schedule 16.01.2012


Ответы (2)


Учитывая, что вы показываете тиковые данные в реальном времени, я бы рекомендовал обратиться к хранилищу данных. Поскольку вы отображаете только 5 элементов из тика, вы можете рассмотреть что-то другое, тогда QMap может быть массивом, поскольку ваша вселенная может быть достаточно стандартизирована в течение торгового дня.

Также я должен предположить, что код является многопоточным, и curTickMap может измениться во время setTickMap, поскольку вполне вероятно, что вы не выполняете сброс модели на каждом тике.

И, как указал webclectic, опубликованный вами код вряд ли скомпилируется.

person Karlson    schedule 16.01.2012

Ух ты, моей тупости нет предела...

Я исправил проблему, и она не имела ничего общего с самой тиковой моделью. Предоставленные образцы кода работают просто отлично. Очевидно, я был слишком глуп, чтобы убедиться, что используется правильный указатель модели.

Это достаточно:

void PriceModel::setTickMap( const QMap<QString,ITick*>& curTickMap ) {
    this->currentTicks = curTickMap;
    reset();
}
person MicroPor    schedule 16.01.2012