Название: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 04, 2012, 14:42
Покурил примеры использования QAbstratcItemModel, решил своять свою модель: Отображать надо список устройств и подлюченных к ним датчиков. Реализовал интерфейс добавил свои методы AddStation/RemoveStation и тут началась чудеса при удалении элемента delete child_items.takeAt(position); Прога валится где-то дальше, отловить где конкретно не удается =\, что странно если я просто удаляю элемент из списка без освобождения памяти все ок! bsbddata.h#ifndef BSBDDATA_H #define BSBDDATA_H #include <QList> #include "treeitembase.h" class Sensor; class Station; typedef QList<Station*> StationList; typedef QList<Sensor*> SensorList;
class Station:public TreeItemBase{ public: Station(const int& id); Station(const int& id,const SensorList& sensor_list); ~Station();
SensorList GetSensorList(); Sensor* GetSensor(const int &vnum); QVariant Data(const int &column=0) const; void SetData(const int &column, const QVariant &value); int ColumnCount() const;
int Id() const; private: const int id;
};
class Sensor:public TreeItemBase{ public: Sensor(const int& id,const int& type,Station *parent = 0); ~Sensor(); //типы упорядочить и сделать по документации enum {BDK,BDU,BMG}; enum {ID,TYPE,VOLTAGE,MEASHURES}; enum {COL0,COL1,COL2}; QVariant Data(const int &column=0) const; void SetData(const int &column, const QVariant &value); int ColumnCount() const;
int Id() const; int Type() const; //Метод получения измерений void SetMeashures(void* m); void* GetMeashures() const; float GetVoltage() const; void SetVoltage(const float& val); private: QString MakeIdAndType() const; QString MakeVoltage() const; QString MakeMeashures() const; const int type; const int id; float voltage;//Напряжение батареи //измерения //QList<double> meashures; //QByteArray meashures; void* meashures;
};
class RootItem:public TreeItemBase{ public: RootItem(const StationList &list=StationList()); ~RootItem(); int ColumnCount() const; QVariant Data(const int &column) const; void SetData(const int &column, const QVariant &value); };
#endif // BSBDDATA_H
bsbddata.cpp#include "bsbddata.h" #include <QtGui> #include "controller.h" Sensor::Sensor(const int& id,const int& type,Station* parent):TreeItemBase(parent),id(id),type(type){ voltage=0; } Sensor::~Sensor(){}
QVariant Sensor::Data(const int &column) const{ QVariant ret_val; //Константанты не соотвествуют! switch(column){ case COL0:{ret_val=MakeIdAndType(); break;} case COL1:{ret_val=MakeVoltage();break;} case COL2:{ret_val=MakeMeashures();break;} } return ret_val; }
void Sensor::SetData(const int &column, const QVariant &value) { switch(column){ //case ID:{ret_val=Id();break;} //case TYPE:{ret_val=Type();break;} case VOLTAGE:{SetVoltage(value.toFloat());break;} case MEASHURES:{break;} } }
int Sensor::ColumnCount() const{ //Колличество полей или может их как строки представлять? return MEASHURES+1; }
int Sensor::Id() const{return id;} int Sensor::Type() const {return type;} //Метод получения измерений void Sensor::SetMeashures(void* m){ if (meashures!=m) meashures=m; }
void* Sensor::GetMeashures() const{return meashures;} float Sensor::GetVoltage() const {return voltage;} void Sensor::SetVoltage(const float& val){ if(voltage!=val){ voltage=val; } }
QString Sensor::MakeIdAndType() const{ Controller* cnt=Controller::GetInstance(); const char *sensor_name[]={ "БДК", "БДУ", "БМГ" }; return cnt->Convert(sensor_name[Type()])+QString(":")+QString::number(Id()); }
QString Sensor::MakeVoltage() const{ Controller* cnt=Controller::GetInstance(); return QString::number(GetVoltage()) +cnt->Convert("В "); }
QString Sensor::MakeMeashures() const{ return QString(); }
Station::Station(const int& id):TreeItemBase(0),id(id){}
Station::Station(const int& id,const SensorList& sensor_list):id(id){ for(int i=0;i<sensor_list.size();i++){ //const TreeItemBase* child=new TreeItemBase(); //AppendChild(child); } } Station::~Station(){} int Station::Id() const {return id;} SensorList Station::GetSensorList(){ //Метод может и не нужен SensorList list; list.push_back(NULL); return list; }
Sensor* Station::GetSensor(const int &vnum){ /*if(vnum>=childCount()){ return NULL; }*/ //return reinterpret_cast<Sensor*>(child(vnum)); return new Sensor(0,Sensor::BDK); }
QVariant Station::Data(const int &column) const{ if (column!=0) return QVariant(); Controller* cnt=Controller::GetInstance(); QString ret_str=cnt->Convert("Станция: ")+QString::number(Id()); return QVariant(ret_str); }
void Station::SetData(const int &column, const QVariant &value) { }
int Station::ColumnCount() const { return 1; }
RootItem::RootItem(const StationList &list):TreeItemBase(0){ for(int i=0;i<list.size();i++){ AppendChild(list.at(i)); } }
RootItem::~RootItem(){}
int RootItem::ColumnCount() const{ return 1; }
QVariant RootItem::Data(const int &column) const { return QVariant("Base station and Sensors"); }
void RootItem::SetData(const int &column, const QVariant &value) { }
bsbdmodel.h#ifndef BSBDMODEL_H #define BSBDMODEL_H #include <QVector> #include <QVariant> #include <QAbstractItemModel> #include "bsbddata.h" #include "controller.h"
class BSBDModel : public QAbstractItemModel{ Q_OBJECT public: explicit BSBDModel(const StationList &list=StationList(),QObject *parent=0); ~BSBDModel(); //Реализация интерфейса QVariant data(const QModelIndex &index, int role) const; QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; //* int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; //Функционал под конкретную модель работы со станциями и датчиками bool AddStation(const int& station_id=0); bool RemoveStation(const int& station_id); bool RemoveSensor(const int& station_id,const int& vnum);
bool AddSensor(const int& station_id,const int& sensor_id=0); bool ClearStation(const int& station_id);
const Station* GetStation(const QModelIndex& index) const; private: /*TreeItemBase**/ RootItem *root; TreeItemBase* getItem(const QModelIndex &index) const; void PrepareTest(); /* SensorData GetSensorData(const int& station_id,const int& sensor_id);*/ };
#endif // BSBDMODEL_H bsbdmodel.cpp#include "bsbdmodel.h" #include <QtCore> BSBDModel::BSBDModel(const StationList &list,QObject *parent):QAbstractItemModel(parent){ root=new RootItem(list); }
BSBDModel::~BSBDModel(){ delete root; //qDeleteAll(root) }
QVariant BSBDModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); //Пока только для отображения if (role != Qt::DisplayRole /*&& role != Qt::EditRole*/) return QVariant();
TreeItemBase *item = getItem(index);
return item->Data(index.column()); }
QModelIndex BSBDModel::index(int row, int column, const QModelIndex &parent) const{ if (parent.isValid() && parent.column() != 0) return QModelIndex();
TreeItemBase *parentItem = getItem(parent);
TreeItemBase *childItem = parentItem->Child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); }
QModelIndex BSBDModel::parent(const QModelIndex &index) const{ TreeItemBase* item=getItem(index); if(item==root) return QModelIndex();
TreeItemBase* parent=item->Parent(); if(parent==NULL){ return QModelIndex(); } return createIndex(parent->ChildCount(),0,parent);
}
int BSBDModel::rowCount(const QModelIndex &parent) const{ TreeItemBase* item=getItem(parent); if(item==NULL) return 0; return item->ChildCount(); }
int BSBDModel::columnCount(const QModelIndex &parent) const{ /*TreeItemBase* item=getItem(parent); if(item==NULL) return 0; return item->ColumnCount();*/ //МАГИЧЕСКАЯ КОНСТАНТА! return 3; } //заголовки QVariant BSBDModel::headerData(int section, Qt::Orientation orientation, int role) const{ if (orientation == Qt::Horizontal && role == Qt::DisplayRole){ const char *col_names[]={ "Станция\Датчик", "Напряжение питания", "Измерения(исходные)" }; Controller* cnt=Controller::GetInstance(); return QVariant(cnt->Convert(col_names[section])); } return QVariant(); }
bool BSBDModel::AddStation(const int &station_id){ //createIndex(root->ChildCount(),0,) Station* newstation=new Station(station_id); QModelIndex root_index=parent(QModelIndex()); int fisrtlast=root->ChildCount(); beginInsertRows(root_index,fisrtlast,fisrtlast); root->AppendChild(newstation); endInsertRows(); return true; }
bool BSBDModel::RemoveStation(const int &station_id){ bool ret_val=false; for(int i=0;i<root->ChildCount();i++){ Station* item=dynamic_cast<Station*>(root->Child(i)); if (item->Id()==station_id){ QModelIndex remove_index=index(i,0,parent(QModelIndex())); beginRemoveRows(remove_index,i,i); root->RemoveChild(i); endRemoveRows(); ret_val=true; break; } } return ret_val; }
TreeItemBase *BSBDModel::getItem(const QModelIndex &index) const{ if (index.isValid()) { TreeItemBase *item = static_cast<TreeItemBase*>(index.internalPointer()); if (item) return item; } return root; }
const Station *BSBDModel::GetStation(const QModelIndex &index) const{ if(!index.isValid()){ return NULL; } return dynamic_cast<Station*>(getItem(index)); }
treeitembase.h#ifndef TREEITEMBASE_H #define TREEITEMBASE_H #include <QList> #include <QVariant> class TreeItemBase;
class TreeItemBase { public: TreeItemBase(TreeItemBase *parent = 0); ~TreeItemBase();
TreeItemBase *Child(const int& number); int ChildCount() const;
//int columnCount() const; void AppendChild(const TreeItemBase *item); //bool insertColumns(int position, int columns); TreeItemBase *Parent(); int Row()const; void RemoveChild(const int& position); //bool removeColumns(int position, int columns);
virtual void SetData(const int& column, const QVariant &value)=0; virtual QVariant Data(const int& column) const=0; //Сколько у нас полей каждый решает сам! virtual int ColumnCount() const=0;
private: QList<TreeItemBase*> child_items; TreeItemBase *parent_item; };
#endif // TREEITEMBASE_H treeitembase.cpp #include "treeitembase.h" #include <QtCore> TreeItemBase::TreeItemBase(TreeItemBase *parent){ parent_item=parent; } TreeItemBase::~TreeItemBase(){ qDeleteAll(child_items); //освободить память выделенную на элементы списка //qDebug() <<"size:"<<child_items.size()<<"\n"; //child_items.clear(); //qDebug() <<"size:"<<child_items.size()<<"\n";
}
TreeItemBase* TreeItemBase::Child(const int& number){ if (number>=child_items.size()) return NULL; return child_items.at(number); }
int TreeItemBase::ChildCount() const{ return child_items.count(); }
void TreeItemBase::AppendChild(const TreeItemBase* child){ child_items.append(const_cast<TreeItemBase*>(child)); //? }
TreeItemBase* TreeItemBase::Parent(){ return parent_item; }
void TreeItemBase::RemoveChild(const int& position){ if (position<child_items.size()){ qDebug()<<"size:"<<child_items.size(); //Валилась ошибка при вызове этого метода delete child_items.takeAt(position); qDebug()<<"size:"<<child_items.size(); } } int TreeItemBase::Row() const{ if (parent_item) return parent_item->child_items.indexOf(const_cast<TreeItemBase*>(this));
return 0; }
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 04, 2012, 16:18
Покурил примеры использования QAbstratcItemModel, решил своять свою модель:
Отображать надо список устройств и подлюченных к ним датчиков. Реализовал интерфейс добавил свои методы AddStation/RemoveStation и тут началась чудеса при удалении элемента delete child_items.takeAt(position); Прога валится где-то дальше, отловить где конкретно не удается =\, что странно если я просто удаляю элемент из списка без освобождения памяти все ок!
Выложи архив с проектом, а то многим лень копировать и восстанавливать проект самому. =)
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 05, 2012, 07:47
Думал наоборот никто не захочет с архивом ковырятся... ::)
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 05, 2012, 13:12
Думал наоборот никто не захочет с архивом ковырятся... ::)
Если бы кода было мало тогда да, качать неохота. Но когда его много, то проще в редакторе. Падает у тебя тут: C++ (Qt) int TreeItemBase::ChildCount() const{ return child_items.count(); <<---Падение }
И мне не нравятся dynamic_cast, так как ты используешь кьют, то используй хотя-бы qobject_cast.
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: Bepec от Апрель 05, 2012, 13:21
Неинициализированная переменная? Или почему у него там падает то? :)
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 05, 2012, 13:52
Неинициализированная переменная? Или почему у него там падает то? :)
Нет, инициализированная ибо является членом класса. Просто увидев динамик каст мне перехотелось дальше разбираться. Пусть сперва автор отпишется.
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 05, 2012, 13:54
Думал наоборот никто не захочет с архивом ковырятся... ::)
Если бы кода было мало тогда да, качать неохота. Но когда его много, то проще в редакторе. Падает у тебя тут: C++ (Qt) int TreeItemBase::ChildCount() const{ return child_items.count(); <<---Падение }
И мне не нравятся dynamic_cast, так как ты используешь кьют, то используй хотя-бы qobject_cast. Спасибо поправил, как-то неудачно они метод обозвали с size() перепутал =( - только это всеравно не помогает всеравно валится,вроде бы ссылается на inline Qlist::size() qobject_cast - требует наследование от QObject оно мне в тех классах не требуется
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 05, 2012, 14:03
Еще перепроверил dynamic_cast - должен корректно срабатывать, так как Station,Sensor являются наследниками от TreItemBase. Поставил проверку на NULL - нулевых указаетелй это не выдает.
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: Bepec от Апрель 05, 2012, 14:03
Указатель не может быть нулевым ;) Даже если он не проинициализирован в нём лежит рандомный мусор :)
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 05, 2012, 14:20
Еще перепроверил dynamic_cast - должен корректно срабатывать, так как Station,Sensor являются наследниками от TreItemBase. Поставил проверку на NULL - нулевых указаетелй это не выдает.
Один из твоих TreItemBase точно поврежден или ты его удаляешь а затем пытаешься обратиться к удаленному, ибо там количество объектов начинает показывать "1594420028" штук. добавлено:Вот я добавил отладочный вывод: Create: 0x3ee648 Create: 0xb265028 Create: 0xb27f618 Create: 0xb264b80 Create: 0xb27f650 Create: 0xb27f678 Count: 2 Object: 0x3ee648 Count: 0 Object: 0xb264b80 Count: 1 Object: 0xb27f650 Create: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Create: 0xb28c578 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 station add: 89 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 0 Object: 0xb28c578 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 size: 1 Delete: 0xb28c578 size: 0 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Count: 0 Object: 0xb27f6e8 Create: 0xb273990 Count: 0 Object: 0xb27f6e8 Count: 1594460188 Object: 0xb26b1d8 Count: 1594460188 Object: 0xb26b1d8 Count: 1594460188 Object: 0xb26b1d8 Count: 0 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 station add: 90 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 0 Object: 0xb273990 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Count: 1 Object: 0xb27f6e8 Create: 0xb294498 Count: 1 Object: 0xb27f6e8 И как видно ошибка в TreItemBase расположенном по 0xb26b1d8, но такой объект не создавался! Вот откуда он взялся? Небось это динамик каст его так скастовал. добавлено:А вот собственно и место которое возвращает указатель на уничтоженный объект: C++ (Qt) QModelIndex BSBDModel::parent(const QModelIndex &index) const{ TreeItemBase* item=getItem(index); << --- 1 qDebug() << "From getItem(index)" << item; if(item==root) return QModelIndex(); TreeItemBase* parent=item->Parent(); << --- 2 qDebug() << "From item->Parent()" << parent; if(parent==NULL){ return QModelIndex(); } return createIndex(parent->ChildCount(),0,parent); << --- 3 }
1. Возвращает указатель на уничтоженный объект 2. Возвращает указатель на мусор 3. А вот тут вызвав мусор и падает программа.
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 05, 2012, 14:46
Указатель не может быть нулевым ;) Даже если он не проинициализирован в нём лежит рандомный мусор :)
Ну так я и проверяю его на неинициализированность ??? Вобщем буду разбиратся с непонятным указателем
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: Bepec от Апрель 05, 2012, 14:52
Указатель на условие "!= NULL" будет реагировать однозначно - не нулл :D
Толку то от таких проверок?
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 05, 2012, 14:58
Поповоду проверок на NULL возможно вы правы - они ничего не дадут. Проблема в том что прога сейчас сыпется при закоментированной строке овобождения памяти.... и не входит в метод parent я не вижу при крахе программы отладчного вывода добавленого V1KT0P Кстати код из примера: TreeItem *TreeModel::getItem(const QModelIndex &index) const { if (index.isValid()) { TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); if (item) return item; //Эта проверка не тоже самое что и Item!=NULL } return rootItem; }
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 05, 2012, 15:11
Поповоду проверок на NULL возможно вы правы - они ничего не дадут. Проблема в том что прога сейчас сыпется при закоментированной строке овобождения памяти.... и не входит в метод parent я не вижу при крахе программы отладчного вывода добавленого V1KT0P Кстати код из примера: TreeItem *TreeModel::getItem(const QModelIndex &index) const { if (index.isValid()) { TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); if (item) return item; //Эта проверка не тоже самое что и Item!=NULL } return rootItem; } Ты удаляешь объект а потом в коде пытаешься к нему обратиться, вот и выясни как так получается.
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: Bepec от Апрель 05, 2012, 15:11
Перевожу
Если (item равняется true) тогда ...
Где ты тут NULL увидел, я уж незнаю ;)
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 05, 2012, 15:15
Все спасибо ща еще раз вдумчиво покурю свой код, а то у меня еще в версиях кода началась путаница =\ ЗЫ про if(item) я чего-то видимо не знаю....
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: Bepec от Апрель 05, 2012, 15:27
Попробуй сам :D
Создай неинициализированный указатель и проверь его на эти условия ;)
PS я долго радовался такому способу проверки указателей. Минуты полторы. До тех пор пока обратился по указателю к какой то памяти и убил систему в BSOD :D
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 05, 2012, 15:49
Все спасибо ща еще раз вдумчиво покурю свой код, а то у меня еще в версиях кода началась путаница =\ ЗЫ про if(item) я чего-то видимо не знаю....
У тебя в функцию: C++ (Qt) BSBDModel::parent
Передается удаленный QModelIndex. Вот только откуда не могу понять.
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: Bepec от Апрель 05, 2012, 17:49
У тебя в функцию: C++ (Qt) BDSMModel::parent
Передается удаленный QModelIndex. Вот только откуда не могу понять. :D А стек вызовов посмотреть не судьба?
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: V1KT0P от Апрель 05, 2012, 18:01
У тебя в функцию: C++ (Qt) BDSMModel::parent
Передается удаленный QModelIndex. Вот только откуда не могу понять. :D А стек вызовов посмотреть не судьба? Конечно смотрел из QAbstractItemView вызывается, а как туда индекс попал без понятия. Мне разбираться даже не охота. Тут явно автор что-то не то делает, либо забывает откуда-то удалить, либо неправильно реализовал логику. Там конечно патч на пару строк решает проблему падения при удалении. Но это бред, надо искать причину а не устранять последствия. добавлено:Короче ошибка появляется только при первом добавлении после удаления. Наверно перед вставкой нового объекта вызываются функции которые пытаются достать этот еще не добавленный объект. Пока что можно временно пофиксить вот так: C++ (Qt) TreeItemBase *BSBDModel::getItem(const QModelIndex &index) const{ if (index.isValid()) { TreeItemBase *item = static_cast<TreeItemBase*>(index.internalPointer()); if (!root->isContains(item)) { qDebug() << "ERROR!!!"; return root; } if (item) return item; } return root; }
C++ (Qt) bool TreeItemBase::isContains(TreeItemBase *item) { return child_items.contains(item); }
Название: Re: Ошибка памяти при работе с моделью дерева
Отправлено: SmileGobo от Апрель 06, 2012, 10:17
Да видимо где-то, я не соблюдаю соглашение по интерфейсу, попробую взять готовую модельку из примера и через наследование свой функционал реализовать.
|