Russian Qt Forum

Программирование => С/C++ => Тема начата: UltraPenguin от Май 28, 2014, 11:07



Название: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Май 28, 2014, 11:07
Доброго времени суток!

После прогона проги через valgrind последний выдал множество ошибок такого рода:
Цитировать
Address 0x10835098 is 8 bytes inside a block of size 16 free'd
==26294==    at 0x4C279DC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26294==    by 0x43674A: CReadWriteINIParam::~CReadWriteINIParam() (ReadWriteINIParam.cpp:59)

Конкретно ругается на строку:
Код:
delete settings;

Само поле settings объявлено так:
Код:
QSettings *settings;

И его инициализация происходит в конструкторе класса CReadWriteINIParam через оператор new.
Почему возникает ошибка обращения к освобожденной памяти, если единственное освобождение находится как раз в деструкторе класса? ???

Если закомментить строку с delete, ошибки пропадут, но возрастут утечки памяти судя по тому, что выдает все тот же valgrind.

Возможно я чего-то недоучил, прошу сильно не ругаться :)

Заранее спасибо!


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: GreatSnake от Май 28, 2014, 11:43
При создании settings parent задавался?


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Май 28, 2014, 11:49
Нет не задавался. Честно говоря, забыл про него, теперь понятно как побороть утечку. Спасибо большое!
Получается если не задан родитель, то поле считается освобожденным к моменту вызова деструктора?


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: GreatSnake от Май 28, 2014, 11:55
Получается если не задан родитель, то поле считается освобожденным к моменту вызова деструктора?
С чего это вдруг?


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Май 28, 2014, 13:54
ну откуда то ошибка об обращении к свободной памяти берется?


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: _Bers от Май 28, 2014, 23:16
ну откуда то ошибка об обращении к свободной памяти берется?

Телепаты в отпуске. Вы даже минимальный код иллюстрирующий проблему не привели.

1. В вашей ИДЕ сделайте "показать использование" на подозрительную переменную. И рассмотрите все места где создается, где меняется, где прибивается.

2. Если первое не помогло - используйте пошаговую отладку. Вам нужно воссоздать картину действия.


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Май 29, 2014, 15:10
Цитировать
Телепаты в отпуске. Вы даже минимальный код иллюстрирующий проблему не привели.
Вроде как телепаты и не требовались. В первом посте, как мне кажется, все достаточно детально описано. Но если нужен минимальный иллюстрирующий код то пожалуйста:
Код:
class CReadWriteINIParam
{
    private:
        QSettings* settings;
}

CReadWriteINIParam::CReadWriteINIParam()
{
    settings = new QSettings(sFileININame, QSettings::IniFormat);
}

CReadWriteINIParam::~CReadWriteINIParam()
{
    if (settings != NULL)
        delete settings;
}

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


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Май 29, 2014, 15:20
1. В вашей ИДЕ сделайте "показать использование" на подозрительную переменную. И рассмотрите все места где создается, где меняется, где прибивается.

2. Если первое не помогло - используйте пошаговую отладку. Вам нужно воссоздать картину действия.

- У меня не включается утюг марки М модели К. Втыкаю в розетку на 220, нажимаю сюда. Что не так?
- Не знаю, попробуйте заснять ваши действия на видео и покадрово все просмотрите еще раз. Вам нужно воссоздать картину действия.

 ;D

Простите, не сдержался :P


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Май 29, 2014, 15:43
При создании settings parent задавался?

Я что-то рано обрадовался по поводу возможности указать родителя. Родителем ведь может быть только класс QObject и его наследники! Неужели единственный способ не вызывать гнев valgrinda, это наследовать ненужный функционал QObject?

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


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: kambala от Май 29, 2014, 18:21
зачем сеттингсам задавать родителя и создавать их в куче?


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: sergek от Май 29, 2014, 19:13
Интересная у вас тут беседа завязалась :)
Хотя, конечно, можно просто закрыть глаза на данные строки valgrinda, память то чистится в любом случае...
Не то слово - даже дважды:
Цитировать
Memcheck keeps track of the blocks allocated by your program with malloc/new, so it can know exactly whether or not the argument to free/delete is legitimate or not. Here, this test program has freed the same block twice. As with the illegal read/write errors, Memcheck attempts to make sense of the address freed. If, as here, the address is one which has previously been freed, you wil be told that -- making duplicate frees of the same block easy to spot. You will also get this message if you try to free a pointer that doesn't point to the start of a heap block.
А попробуйте закомментировать весь код, использующий созданный settings, кроме new/delete и прогнать через valgrind. Интересно, останется ошибка?


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: _Bers от Май 29, 2014, 23:13
Цитировать
Телепаты в отпуске. Вы даже минимальный код иллюстрирующий проблему не привели.
Вроде как телепаты и не требовались. В первом посте, как мне кажется, все достаточно детально описано. Но если нужен минимальный иллюстрирующий код то пожалуйста:
Код:
class CReadWriteINIParam
{
    private:
        QSettings* settings;
}

CReadWriteINIParam::CReadWriteINIParam()
{
    settings = new QSettings(sFileININame, QSettings::IniFormat);
}

CReadWriteINIParam::~CReadWriteINIParam()
{
    if (settings != NULL)
        delete settings;
}

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

Эта выдержка кода не иллюстрирует проблему. И вообще не соответствует действительности.
Непонятно для чего вы её привели вместо того, что бы привести выдержку реального кода.
Возможно вам просто лень решать собственную проблему.

По поводу пошаговой отладки: программист полагает. А программа располагает.
Очевидно, что в программе происходят действия, которых вы не ожидаете.

Пошаговая отладка может помочь понять, в чем именно вы ошиблись.




Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: _Bers от Май 29, 2014, 23:18
Код:
CReadWriteINIParam::~CReadWriteINIParam()
{
    if (settings != NULL)
        delete settings;
}

Этот код вызывает сомнение.

1. Вы допускаете, что к моменту запуска диструктора setting может быть равен nullptr ?
Каким образом это может произойти?
 --- конструктор не захватил ресурс по указателю?
 --- существуют методы, которые могут освободить ресурс в процессе жизни экземпляра класс?

 Если второй пункт имеет место быть - стоит рассмотреть его внимательнее.

2. Нет ни одной причины проверять указатель на nullptr перед освобождением ресурса.


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Июнь 03, 2014, 16:45
Эта выдержка кода не иллюстрирует проблему. И вообще не соответствует действительности.
Подождите, вы просили МИНИМАЛЬНЫЙ код иллюстрирующий проблему. Вот он.

Непонятно для чего вы её привели вместо того, что бы привести выдержку реального кода.
По разным соображениям, но в первую очередь из-за того, что его МНОГО.

По поводу пошаговой отладки: программист полагает. А программа располагает.
Очевидно, что в программе происходят действия, которых вы не ожидаете.
Пошаговая отладка может помочь понять, в чем именно вы ошиблись.
Ок, я вас понимаю. Но я спрашивал о том, КАК конкретно проверить указывает ли указатель (масло так маслит ;D)  на свободную память или нет с помощью дебагера если в коде по ходу выполнения НЕТ delet'ов кроме указанного мной в минимальном примере кода?

UPD: я вот не в курсе как это сделать. Возможно, недоучил. Но скорее всего это просто никак не узнать)


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Июнь 03, 2014, 16:49
Цитировать
А попробуйте закомментировать весь код, использующий созданный settings, кроме new/delete и прогнать через valgrind. Интересно, останется ошибка?
ок попробую, напишу результат


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: _Bers от Июнь 04, 2014, 00:20
Подождите, вы просили МИНИМАЛЬНЫЙ код иллюстрирующий проблему. Вот он.

Вы ошибаетесь. Это не он. Этот код не иллюстрирует проблему.

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

Ну и самое главное, он должен демонстрировать проблему.

...но в первую очередь из-за того, что его МНОГО.

Понятно... что ж, в таком случае остается только эвристика.

Ок, я вас понимаю. Но я спрашивал о том, КАК конкретно проверить указывает ли указатель (масло так маслит ;D)  на свободную память или нет с помощью дебагера если в коде по ходу выполнения НЕТ delet'ов кроме указанного мной в минимальном примере кода?

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

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

Цитировать
А попробуйте закомментировать весь код, использующий созданный settings, кроме new/delete и прогнать через valgrind. Интересно, останется ошибка?
ок попробую, напишу результат

Второе, что бы я сделал: в иде запросил бы на имя settings "найти использование".
Во многих случаях это позволяет обнаружить ошибку путем анализа использования без необходимости отключать куски кода.







Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: UltraPenguin от Июнь 04, 2014, 19:24
Эх. Это действительно ТОТ код на который valgrind дает такое сообщение. Я понимаю что такое "код иллюстрирующий проблему". ;)
В том то все и дело, что данные там высвечиваются валидные все время работы программы.

Интересный вопрос: что будет показывать дебагер, если память под указателем освобождена, но ОС еще не затерла лежащую по данному адресу инфу?

У меня была подобная ситуация, и на экране дебагера я любовался на верные на первый взгляд данные.


Название: Re: Правильное освобождение ссылочных полей объекта
Отправлено: Igors от Июнь 05, 2014, 10:06
Интересный вопрос: что будет показывать дебагер, если память под указателем освобождена, но ОС еще не затерла лежащую по данному адресу инфу?

У меня была подобная ситуация, и на экране дебагера я любовался на верные на первый взгляд данные.
"Затирание" происходит сразу т.к. ОС вписывает в освобожденный блок связки (типа указатель на след блок)
Код
C++ (Qt)
delete a;
int test = a->data;  // "ведь еще ничего не случилось" - неверно, часть данных уже перетерта
 

Возвращаясь к исходному вопросу - неясно из-за чего сыр-бор. Печатайте счетчики в конструкторе и деструкторе, если они сбиваются - проблемы valgrind