Никак не могу отловить ошибку.
Вроде все что создавал на куче удаляю за собой.
И все равно выдает.
завершился с кодом -1073741819
Использую библиотеку QWT
когда в дебаге отлавливаю то программа вылетает здесь:
template <typename T>
QwtPlotSeriesItem<T>::~QwtPlotSeriesItem()
{
delete d_series;
}
void Widget::sl_deletePlot(QTreeWidgetItem*item,int column)
{
qDebug()<<"sl_deletePlot";
qDebug()<<"plot = "<<((TreeWidgetItem*)item)->p;
((TreeWidgetItem*)item)->p->deleteLater(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
listPlot.removeOne(((TreeWidgetItem*)item)->p);
}
не выводи код ошибки в десятичном виде. перевод в шестнадцатиричный даёт нормальный читабельный код ошибки и по нему сразу всё понятно.
0xC0000005 - это ошибка обращения к памяти. классика жанра.
где-то кто-то обращается к удалённому объекту. или вылетает за границу массива. надо весь код смотреть, по куску не понять, что там удаляется зря.
PS: так выводит сам Qt Creator, по этому - увы
Ноосфера подсказывает мне что дело в двойном удалении item->p.
((TreeWidgetItem*)item)->p->deleteLater(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
listPlot.removeOne(((TreeWidgetItem*)item)->p);
void Widget::sl_deletePlot(QTreeWidgetItem*item,int column)
{
qDebug()<<"sl_deletePlot";
if( (((TreeWidgetItem*)item)->checkState(0) == Qt::Checked) && (((TreeWidgetItem*)item)->p != NULL) )
{
qDebug()<<"plot = "<<((TreeWidgetItem*)item)->p;
listPlot.removeOne(((TreeWidgetItem*)item)->p);
((TreeWidgetItem*)item)->p->deleteLater();
}
}
((TreeWidgetItem*)item)->p // это указатель на плот, который принадлежит item
class Plot;
class TreeWidgetItem: public QObject, public QTreeWidgetItem
{
Q_OBJECT
public:
Plot* p;
public:
explicit TreeWidgetItem(TreeWidgetItem*parent);
explicit TreeWidgetItem(QTreeWidget*parent);
explicit TreeWidgetItem(QTreeWidgetItem*parent);
~TreeWidgetItem();
};
connect(tree,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this,SLOT(sl_deletePlot(QTreeWidgetItem*,int)));
необходимость явного приведения - уже признак кривизны кода
((TreeWidgetItem*)item)->p
скажи, зачем это делаешь ?
demaker,
указатель item должен уметь рассказывать это без явного приведения. Либо через виртуальную функцию, либо через dynamic_cast, либо через стороннюю ассоциативную таблицу
Чтобы долго всем мозги догадками не компостировать, прицепи проект ))
Сча подцеплю
А что архив нельзя
Могу по файлу
У файлы не цепляет, может на мыло, если не против, то вышли
zip архив
или сюда zalil.ru
Отправил на залил
архив(Rar) untitled
да и cfg-файл и dat-файл
тоже
сча скину на zalil
Все скинул
А мне ссылку на zalil?
demaker, cfg и dat не нужны. Плоттер тоже - сделай так, чтобы было только дерево с проблемой. сразу туда добавь элементы. Чтобы просто запустить и увидеть падение
Заводится переменная:
data = new QwtPointArrayData(ct->getTimeDataVector(fn_dat+".DAT"),
ct->getAnalogDataVector(fn_dat+".DAT", number_chanel),
ct->DynamicCfg->NumSamples);
curve->setData(data);
delete data;
data = new QwtPointArrayData(ct->getTimeDataVector(fn_dat+".DAT"),
ct->getAnalogDataVector(fn_dat+".DAT", number_chanel),
ct->DynamicCfg->NumSamples);
curve->setData(data);
delete data;
А в каком месте вылетает?
void Widget::sl_deletePlot(QTreeWidgetItem*item,int column)
{
qDebug()<<"sl_deletePlot";
if( (((TreeWidgetItem*)item)->checkState(0) == Qt::Checked) && (((TreeWidgetItem*)item)->p != NULL) )
{
qDebug()<<"plot = "<<((TreeWidgetItem*)item)->p;
listPlot.removeOne(((TreeWidgetItem*)item)->p);
((TreeWidgetItem*)item)->p->deleteLater();//!!!!!!!!!!!!!!!!!!!!!!!!!!
((TreeWidgetItem*)item)->setCheckState(0,Qt::Unchecked);
}
}
То же самое.
Plot* plot = new Plot(c.Filename,c.type,c.channel_num,this);
Согласен. Но также вылетает - 255 дает
void Widget::dropEvent(QDropEvent *event)
{
...
Plot* plot = new Plot(c.Filename,c.type,c.channel_num);
vbl_plot->addWidget(plot);
listPlot.append(plot);
...
}
Widget::~Widget()
{
delete ui;
for(int i = 0; i<listPlot.length();i++)
{
listPlot.at(i)->deleteLater();
}
listPlot.clear();
items.clear();
}
int TreeWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QTreeWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: sg_itemChecked((*reinterpret_cast< TreeWidgetItem*(*)>(_a[1]))); break;
default:;
}
_id -= 1;
}
return _id;
}
Ага, а deleteLater остался в sl_deletePlot? Хотя не должно влиять там они и из листа удаляются.
for(int i = 0; i<listPlot.length();i++)
{
listPlot.at(i)->deleteLater();
}
listPlot.clear();
connect(tree,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this,SLOT(sl_deletePlot(QTreeWidgetItem*,int)));
listPlot.removeOne(((TreeWidgetItem*)item)->p);
((TreeWidgetItem*)item)->p->deleteLater();
Мне не нравятся эти deleteLater в деструкторе.
Виджет разрушается уже после выхода приложения из основного цикла, поэтому делет лэйтер может не сработать, да и вообще хз как он работает в завершившемся приложении. Можно попробовать тупо закомментить его, посмотреть что будет, если ошибка пройдет значит в нем дело.
listPlot.removeOne(((TreeWidgetItem*)item)->p);
//((TreeWidgetItem*)item)->p->deleteLater();
((TreeWidgetItem*)item)->setCheckState(0,Qt::Unchecked);
Не, не эти deleteLater .)
Вот эти
for(int i = 0; i<listPlot.length();i++)
{
listPlot.at(i)->deleteLater();
}
Не, все так же
нужно:
1) решить, какой класс управляет данными в массиве (в частности - в мапе, в списке)
2) инкапсулировать массив в этот класс с доступом private
3) сделать методы Clear(), DeleteItem(), .... , AddItem(), FindItem(), ...
4) из конструктора класса вызвать Clear()
и не мучать себя и остальных
и, естественно, никаких deleteLater
как удалить - это зависит от того, как добавлял.
К примеру, ты в какой-то момент времени создаёшь на куче через new и добавляешь к плоттеру (теперь плоттер САМ заботится об удалении графика - в деструкторе это произойдёт) . Если ты извлёк график (навроде removeitem) , то плоттер уже не заботится о его судьбе. Ты можешь сразу после извлечения удалить память графика при помощи delete - так как сам он не удалится. Но это просто утечка памяти, а не выпадение
Придерживайся правила - где создал объект, там и удаляй.
В одном классе.
В двух методах одного класса (create/delete).
В одном методе (на стеке, к примеру) .
В одном потоке. Не надо делать так - в одном потоке создал, в другом удалил.
В одном процессе.
Это желательно Так меньше ошибок
Так, а ларчик просто открывался
Все падает в ~CCOMTRADE, когда удаляются неинициализированные
if(TimeDataVector != NULL) delete[] TimeDataVector;
if(AnalogDataVector != NULL) delete[] AnalogDataVector;
if(DigitalDataVector != NULL) delete[] DigitalDataVector;
TimeDataVector = NULL;
AnalogDataVector = NULL;
DigitalDataVector = NULL;
ну, или std::vector / std::map (лично я кутешные контейнеры стараюсь не использовать, если только никак без этого)
тогда такие забывания просто не существуют
Понятно, спасибо.
Но у меня вроде так и есть:
деструктор:
Widget::~Widget()
{
for(int i = 0; i<listPlot.length();i++)
{
listPlot.at(i)->deleteLater();
}
listPlot.clear();
items.clear();
delete ui;
}
void Widget::sl_deletePlot(QTreeWidgetItem*item,int column)
{
qDebug()<<"sl_deletePlot";
if( (((TreeWidgetItem*)item)->checkState(0) == Qt::Checked) && (((TreeWidgetItem*)item)->p != NULL) )
{
qDebug()<<"plot = "<<((TreeWidgetItem*)item)->p;
listPlot.removeOne(((TreeWidgetItem*)item)->p);
((TreeWidgetItem*)item)->p->deleteLater();
((TreeWidgetItem*)item)->setCheckState(0,Qt::Unchecked);
}
}
void Widget::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat("application/x-qt-windows-mime;value=\"ComtradeChannel\""))
{
QByteArray d(event->mimeData()->data("application/x-qt-windows-mime;value=\"ComtradeChannel\""));
if (d != QVariant(-1).toByteArray())
{
qDebug()<<"d = "<<d;
comtrade_curve_t c= possible_curves.at(d.at(0));
qDebug()<<c.Filename;
qDebug()<<c.type;
qDebug()<<c.channel_num;
event->acceptProposedAction();
Plot* plot = new Plot(c.Filename,c.type,c.channel_num,0);
vbl_plot->addWidget(plot);
listPlot.append(plot);
qDebug() <<"number = "<<index;
plot->item = items.at(index);
items.at(index)->p = plot;
qDebug() <<"plot = "<<items.at(index)->p;
}
else
{
}
}
}
вот это
listPlot.removeOne(((TreeWidgetItem*)item)->p);
((TreeWidgetItem*)item)->p->deleteLater();
((TreeWidgetItem*)item)->setCheckState(0,Qt::Unchecked);
listPlot.removeOne(item);
item->delete_my_p();
//delete item; возможно, это тоже тут
...::delete_my_p()
{
delete p;
p=0;
}
Понятно.
Ну в item должен быть указатель на plot
за этим я и создал TreeWidgetitem от QTreeWidgetitem
но сигнал itemDoubleClicked(QTreeWidgetItem*,int) передает только QTreeWidgetItem*, поэтому приходится делать явное преобразование типов ((TreeWidgetItem*)item)->p
lanz, Алексей1153 огромное спасибо ВАМ!!!
demaker, не должно быть таких преобразований. Что-то не так делаешь
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)