Russian Qt Forum
Октябрь 01, 2024, 07:18 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Ошибка памяти при работе с моделью дерева  (Прочитано 9721 раз)
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;
}
Записан
V1KT0P
Гость
« Ответ #1 : Апрель 04, 2012, 16:18 »

Покурил примеры использования QAbstratcItemModel, решил своять свою модель:

Отображать надо список устройств и подлюченных к ним датчиков. Реализовал интерфейс добавил свои методы AddStation/RemoveStation и тут началась чудеса при удалении элемента delete child_items.takeAt(position); Прога валится где-то дальше, отловить где конкретно не удается =\, что странно если я просто удаляю элемент из списка без освобождения памяти все ок!
Выложи архив с проектом, а то многим лень копировать и восстанавливать проект самому. =)
Записан
SmileGobo
Гость
« Ответ #2 : Апрель 05, 2012, 07:47 »

Думал наоборот никто не захочет с архивом ковырятся... Строит глазки
Записан
V1KT0P
Гость
« Ответ #3 : Апрель 05, 2012, 13:12 »

Думал наоборот никто не захочет с архивом ковырятся... Строит глазки
Если бы кода было мало тогда да, качать неохота. Но когда его много, то проще в редакторе.
Падает у тебя тут:
Код
C++ (Qt)
int TreeItemBase::ChildCount() const{
   return child_items.count(); <<---Падение
}
И мне не нравятся dynamic_cast, так как ты используешь кьют, то используй хотя-бы qobject_cast.
Записан
Bepec
Гость
« Ответ #4 : Апрель 05, 2012, 13:21 »

Неинициализированная переменная? Или почему у него там падает то? Улыбающийся
Записан
V1KT0P
Гость
« Ответ #5 : Апрель 05, 2012, 13:52 »

Неинициализированная переменная? Или почему у него там падает то? Улыбающийся
Нет, инициализированная ибо является членом класса. Просто увидев динамик каст мне перехотелось дальше разбираться. Пусть сперва автор отпишется.
Записан
SmileGobo
Гость
« Ответ #6 : Апрель 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 оно мне в тех классах  не требуется

Записан
SmileGobo
Гость
« Ответ #7 : Апрель 05, 2012, 14:03 »

Еще перепроверил dynamic_cast - должен корректно срабатывать, так как Station,Sensor являются наследниками от TreItemBase.
Поставил проверку на NULL  - нулевых указаетелй это не выдает.
Записан
Bepec
Гость
« Ответ #8 : Апрель 05, 2012, 14:03 »

Указатель не может быть нулевым Подмигивающий Даже если он не проинициализирован в нём лежит рандомный мусор Улыбающийся
Записан
V1KT0P
Гость
« Ответ #9 : Апрель 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. А вот тут вызвав мусор и падает программа.
« Последнее редактирование: Апрель 05, 2012, 14:45 от V1KT0P » Записан
SmileGobo
Гость
« Ответ #10 : Апрель 05, 2012, 14:46 »

Указатель не может быть нулевым Подмигивающий Даже если он не проинициализирован в нём лежит рандомный мусор Улыбающийся

Ну так я и проверяю его на неинициализированность  Непонимающий

Вобщем буду разбиратся с непонятным указателем
Записан
Bepec
Гость
« Ответ #11 : Апрель 05, 2012, 14:52 »

Указатель на условие "!= NULL" будет реагировать однозначно - не нулл Веселый

Толку то от таких проверок?
Записан
SmileGobo
Гость
« Ответ #12 : Апрель 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;
}
« Последнее редактирование: Апрель 05, 2012, 15:05 от SmileGobo » Записан
V1KT0P
Гость
« Ответ #13 : Апрель 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;
}
Ты удаляешь объект а потом в коде пытаешься к нему обратиться, вот и выясни как так получается.
Записан
Bepec
Гость
« Ответ #14 : Апрель 05, 2012, 15:11 »

Перевожу

Если (item равняется true) тогда ...

Где ты тут NULL увидел, я уж незнаю Подмигивающий

Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.25 секунд. Запросов: 20.