Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Общие вопросы _ код ошибки -1073741819

Автор: demaker 1.2.2013, 15:59

Никак не могу отловить ошибку.
Вроде все что создавал на куче удаляю за собой.

И все равно выдает.

завершился с кодом -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);
}


Может кто-то сталкивался???

Автор: Iron Bug 1.2.2013, 21:10

не выводи код ошибки в десятичном виде. перевод в шестнадцатиричный даёт нормальный читабельный код ошибки и по нему сразу всё понятно.
0xC0000005 - это ошибка обращения к памяти. классика жанра.
где-то кто-то обращается к удалённому объекту. или вылетает за границу массива. надо весь код смотреть, по куску не понять, что там удаляется зря.


Автор: RazrFalcon 2.2.2013, 1:58

PS: так выводит сам Qt Creator, по этому - увы

Автор: Iron Bug 2.2.2013, 17:25

Цитата(RazrFalcon @ 2.2.2013, 4:58) *
PS: так выводит сам Qt Creator, по этому - увы

садизм какой-то. причём неоправданный :D

Автор: Litkevich Yuriy 3.2.2013, 16:20

Цитата(demaker @ 1.2.2013, 17:59) *
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);
}
Можно получить комментарий, к каждой строчке? Я не понимаю того, что здесь делается.

Особенно интересует разбор этого:
((TreeWidgetItem*)item)->p

Автор: lanz 4.2.2013, 8:45

Ноосфера подсказывает мне что дело в двойном удалении item->p.

((TreeWidgetItem*)item)->p->deleteLater();    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
listPlot.removeOne(((TreeWidgetItem*)item)->p);


Сначала removeOne удаляет элемент, затем управление возвращается в event loop и выполняется удаление по deleteLater.
Можно попробовать убрать deleteLater.
Еще возможно, если item был создан с parent то parent его удалит (это будет уже третье удаление).

Для диагностики можно добавить печаталку в деструктор.

Автор: demaker 4.2.2013, 11:54

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)));


по коннектету
вызывается слот для удаления плота

Автор: Алексей1153 4.2.2013, 12:01

необходимость явного приведения - уже признак кривизны кода :)

((TreeWidgetItem*)item)->p

скажи, зачем это делаешь ?

Автор: demaker 4.2.2013, 12:06

Цитата(Алексей1153 @ 4.2.2013, 13:01) *
необходимость явного приведения - уже признак кривизны кода :)

((TreeWidgetItem*)item)->p

скажи, зачем это делаешь ?


Чтобы знать какому item принадлежит какой plot

((TreeWidgetItem*)item)->p
Потому что сигнал itemDoubleClicked(QTreeWidgetItem*,int) !!!QTreeWidgetItem
а у меня TreeWidgetItem

Автор: Алексей1153 4.2.2013, 12:09

demaker,
указатель item должен уметь рассказывать это без явного приведения. Либо через виртуальную функцию, либо через dynamic_cast, либо через стороннюю ассоциативную таблицу


Чтобы долго всем мозги догадками не компостировать, прицепи проект ))


Автор: demaker 4.2.2013, 12:23

Сча подцеплю

А что архив нельзя :blink:

Могу по файлу

У файлы не цепляет, может на мыло, если не против, то вышли

Автор: Алексей1153 4.2.2013, 12:25

zip архив

или сюда zalil.ru

Автор: demaker 4.2.2013, 12:35

Отправил на залил
архив(Rar) untitled

да и cfg-файл и dat-файл
тоже
сча скину на zalil

Все скинул :)

Автор: lanz 4.2.2013, 13:07

А мне ссылку на zalil?

Автор: demaker 4.2.2013, 13:23

Цитата(Алексей1153 @ 4.2.2013, 13:25) *
zip архив

или сюда zalil.ru


http://zalil.ru/34229242

Цитата(demaker @ 4.2.2013, 14:21) *
Цитата(Алексей1153 @ 4.2.2013, 13:25) *
zip архив

или сюда zalil.ru


http://zalil.ru/34229242
http://zalil.ru/34229246 -> cfg-файл
http://zalil.ru/34229254 -> dat-файл



Автор: Алексей1153 4.2.2013, 13:34

demaker, cfg и dat не нужны. Плоттер тоже - сделай так, чтобы было только дерево с проблемой. сразу туда добавь элементы. Чтобы просто запустить и увидеть падение

Автор: lanz 4.2.2013, 14:03

Заводится переменная:

data = new QwtPointArrayData(ct->getTimeDataVector(fn_dat+".DAT"),
                                     ct->getAnalogDataVector(fn_dat+".DAT", number_chanel),
                                     ct->DynamicCfg->NumSamples);


Дальше теряется ownership!
curve->setData(data);

Из документации:
Цитата
QwtPlotSeriesItem< T >::setData
Warning:
The item takes ownership of the data object, deleting it when its not used anymore.


Теперь удаляется data!
delete data;

А потом ее удаляет еще раз тот кто ей владеет(curve).
И соответственно падает, т.к. она вручную удалена в деструкторе Plot.

Надо удалить delete из деструктора Plot.

Автор: demaker 4.2.2013, 15:08

Цитата(lanz @ 4.2.2013, 15:03) *
Заводится переменная:
data = new QwtPointArrayData(ct->getTimeDataVector(fn_dat+".DAT"),
                                     ct->getAnalogDataVector(fn_dat+".DAT", number_chanel),
                                     ct->DynamicCfg->NumSamples);


Дальше теряется ownership!
curve->setData(data);

Из документации:
Цитата
QwtPlotSeriesItem< T >::setData
Warning:
The item takes ownership of the data object, deleting it when its not used anymore.


Теперь удаляется data!
delete data;

А потом ее удаляет еще раз тот кто ей владеет(curve).
И соответственно падает, т.к. она вручную удалена в деструкторе Plot.

Надо удалить delete из деструктора Plot.


Сделал как вы сказали, работает.
Но аналоговые плоты удаляет, а дескретные нет, точнее в дебаге удаляет, а если просто запустить то вылетает
с ошибкой
завершился с кодом 255

Или завершился с кодом -1073741819

Автор: lanz 4.2.2013, 15:43

А в каком месте вылетает?

Автор: demaker 4.2.2013, 15:47

Цитата(lanz @ 4.2.2013, 16:43) *
А в каком месте вылетает?


При удалении плота

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);
    }
}

Автор: lanz 4.2.2013, 16:08

То же самое.

Plot* plot = new Plot(c.Filename,c.type,c.channel_num,this);

Здесь plot становится дочерним виджетом widget, потом удаляется deleteLater, потом второй раз удаляется при удалении widget (т.к. входит в иерархию QObject-ов)

Надо удалить deleteLater.
Напомнило анекдот
"-Доктор, мне больно когда я вот-так делаю.
-Не делайте так. Следующий!"
:lol:

Автор: demaker 5.2.2013, 9:18

Согласен. Но также вылетает - 255 дает

Цитата(demaker @ 5.2.2013, 10:07) *
Согласен. Но также вылетает - 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();
}


но не помогает.

Автор: demaker 5.2.2013, 10:34

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;
}

вот в этой функции, когда в дебаге отлаживаю зависает и не выходит

хотя нет - но в дебаге работает нормально, а так :unsure: не понимаю почему

Автор: lanz 5.2.2013, 12:05

Ага, а deleteLater остался в sl_deletePlot? Хотя не должно влиять там они и из листа удаляются.

Автор: demaker 5.2.2013, 12:14

Цитата(lanz @ 5.2.2013, 13:05) *
Ага, а deleteLater остался в sl_deletePlot? Хотя не должно влиять там они и из листа удаляются.


В листе у нас вроде :blink: указатели на плоты, а не сами плоты.
Может я ошибаюсь :huh:

Поэтому мы по списку идем и удаляем.
Правильно?

 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();

Автор: lanz 5.2.2013, 12:16

Мне не нравятся эти deleteLater в деструкторе.
Виджет разрушается уже после выхода приложения из основного цикла, поэтому делет лэйтер может не сработать, да и вообще хз как он работает в завершившемся приложении. Можно попробовать тупо закомментить его, посмотреть что будет, если ошибка пройдет значит в нем дело.

Автор: demaker 5.2.2013, 12:26

Цитата(lanz @ 5.2.2013, 13:16) *
Мне не нравятся эти deleteLater в деструкторе.
Виджет разрушается уже после выхода приложения из основного цикла, поэтому делет лэйтер может не сработать, да и вообще хз как он работает в завершившемся приложении. Можно попробовать тупо закомментить его, посмотреть что будет, если ошибка пройдет значит в нем дело.


Закоментил

listPlot.removeOne(((TreeWidgetItem*)item)->p);
//((TreeWidgetItem*)item)->p->deleteLater();
((TreeWidgetItem*)item)->setCheckState(0,Qt::Unchecked);


при двойном клике на item, плот не закрывается, и не вылетает.
а когда виджет закрываю, то в консоле
untitled.exe завершился с кодом -1073741819

Вся фигня, когда я добавляю графики с цифровым сигналом(digital)
А с аналоговыми(analog) все нормально. :huh:

Автор: lanz 5.2.2013, 13:24

Не, не эти deleteLater .)

Вот эти

    for(int i = 0; i<listPlot.length();i++)
    {
        listPlot.at(i)->deleteLater();
    }


Автор: demaker 5.2.2013, 13:41

Не, все так же

Автор: Алексей1153 5.2.2013, 13:48

нужно:

1) решить, какой класс управляет данными в массиве (в частности - в мапе, в списке)
2) инкапсулировать массив в этот класс с доступом private
3) сделать методы Clear(), DeleteItem(), .... , AddItem(), FindItem(), ...
4) из конструктора класса вызвать Clear()

и не мучать себя и остальных :D

и, естественно, никаких deleteLater

Автор: demaker 5.2.2013, 14:03

Цитата(Алексей1153 @ 5.2.2013, 14:48) *
нужно:

1) решить, какой класс управляет данными в массиве (в частности - в мапе, в списке)
2) инкапсулировать массив в этот класс с доступом private
3) сделать методы Clear(), DeleteItem(), .... , AddItem(), FindItem(), ...
4) из конструктора класса вызвать Clear()

и не мучать себя и остальных :D

и, естественно, никаких deleteLater


:) ок -> понял


И еще такой вопрос по поводу deleteLater.

Как мне удалить график, который я добавил на виджет?
Чуть подробнее можно. :)

Автор: Алексей1153 5.2.2013, 14:07

как удалить - это зависит от того, как добавлял.

К примеру, ты в какой-то момент времени создаёшь на куче через new и добавляешь к плоттеру (теперь плоттер САМ заботится об удалении графика - в деструкторе это произойдёт) . Если ты извлёк график (навроде removeitem) , то плоттер уже не заботится о его судьбе. Ты можешь сразу после извлечения удалить память графика при помощи delete - так как сам он не удалится. Но это просто утечка памяти, а не выпадение

Придерживайся правила - где создал объект, там и удаляй.
В одном классе.
В двух методах одного класса (create/delete).
В одном методе (на стеке, к примеру) .
В одном потоке. Не надо делать так - в одном потоке создал, в другом удалил.
В одном процессе.

Это желательно :) Так меньше ошибок

Автор: lanz 5.2.2013, 14:22

Так, а ларчик просто открывался :lol:
Все падает в ~CCOMTRADE, когда удаляются неинициализированные

    if(TimeDataVector != NULL) delete[] TimeDataVector;
    if(AnalogDataVector != NULL) delete[] AnalogDataVector;
    if(DigitalDataVector != NULL) delete[] DigitalDataVector;


Лечится добавлением в конструктор
TimeDataVector = NULL;
AnalogDataVector = NULL;
DigitalDataVector = NULL;


Но вообще Алексей1153 дело говорит.
И еще поменьше new/delete, а вместо них побольше QVector-ов.

Автор: Алексей1153 5.2.2013, 14:26

ну, или std::vector / std::map (лично я кутешные контейнеры стараюсь не использовать, если только никак без этого)

тогда такие забывания просто не существуют

Автор: demaker 5.2.2013, 14:27

Понятно, спасибо.
Но у меня вроде так и есть:

деструктор:

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
        {
        }
    }
}


Не могу понять что нето. :unsure:
Спасибо.
Попробую заново переписать.

Автор: Алексей1153 5.2.2013, 14:39

вот это

        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;
}

Автор: demaker 5.2.2013, 15:09

Понятно.

Ну в item должен быть указатель на plot
за этим я и создал TreeWidgetitem от QTreeWidgetitem

но сигнал itemDoubleClicked(QTreeWidgetItem*,int) передает только QTreeWidgetItem*, поэтому приходится делать явное преобразование типов ((TreeWidgetItem*)item)->p

lanz, Алексей1153 огромное спасибо ВАМ!!!

Автор: Алексей1153 5.2.2013, 18:32

demaker, не должно быть таких преобразований. Что-то не так делаешь

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)