Доброго дня всем!Есть вопрос по поводу утечки памяти ( memory leak ) в C++.
Я пишу приложение под Qt, и на сколько я знаю Qt сам как бы
освобождает все указатели и все такое. Я не очень в кое-чем уверен, поэтому у меня куча вопросов:Пишу в топик по C++, так как по большей части здесь будет именно про C++...
if ( int i = 0; i < 25; ++i ) {
...
QLabel *mixDevLabel = new QLabel;
...
}Если посмотреть на этот код, то видно что утечка есть, так как адрес на который указывал mixDevLabel
каждый раз перезаписывается ( если я правильно понимаю ).
Не понимаю как Qt сам умудряется освободить память ?!Я вижу только такое решение как освободить потом всю память:
// .hpp
...
QSlider **slider;
...// .cpp
MainWindow::MainWindow ( ) {
...
slider = new QSlider * [ 25 ];
...
if ( int i = 0; i < 25; ++i ) {
...
slider [ i ] = new QSlider [ 1 ] ;
...
}
...
};MainWindow::~MainWindow ( ) {
for ( int i = 0; i < 25; i++ ) {
delete [ ] slider [ i ];
}
delete [ ] slider;
}То есть для этого надо знать что потом освобождать, а для этого как минимум надо
сделать каждый объект разным ( при помощи двухмерного массива, к примеру ).
И теперь мы можем обратится к объекту как к slider [ i ].
И освобождать память так же - через [ i ].А как можно освободить память в случае Qt, если один и то же объект инициализируется разным адресом каждый раз?
Вот как проверить что Qt действительно освобождает память?Пробовал valgrind, ИМХО он не совсем корректно показывает утечку ( часто показывает в нормальных приложениях утечку, то
ли это родная утечка Qt, че-ли? ).Я подумал так: если узнать адреса на которые он указывал, а потом проверить свободные они или нет.
Это можно как то организовать?if ( int i = 0; i < 25; ++i ) {
...
std::cout << mixDevLabel << std::endl;
QLabel *mixDevLabel = new QLabel;
...
}Это выведет на экран адреса на которые указывал указатель, но как проверить действительно ли они освободились?
И еще несколько вопросов на эту тему.
1. Кто на практике знает, много ли программ под UNIX имеет утечку и на сколько она большая?
2. Есть ли программа для просмотра ( доступа ) памяти под UNIX? ( Помню под винду была написана на Delphi )
3. Средства для контроля утечкиУказатели:
Как я понимаю нету способов узнать адрес самого указателя?
int *p;
Тут мы создаем указатель но тип int.Если я правильно понимаю, он сейчас может указывать на что-угодно, и содержать тоже какое-угодно значение.
Но тогда непонятно вот что: если запустить к примеру вот такой кусок кода:#include <iostream>
int main() {
int *p;
std::cout << *p << std::endl;
std::cout << p << std::endl;}
то каждый раз он покажет разный адрес - но одинаковое значение.
Как это может быть? Если каждый раз меняется адрес на который он указывает, то соответственно доложено меняется значение.Далее...
Вот такой кусок кода приведет к ошибке сегментирования:Qt *p;
*p = 5;
Так как мы пытаемся записать число 5 в не положенную нам область памяти ( если я правильно понимаю )
но,
int *p = new int;
*p = 5;
Все нормально. Если я правильно понимаю, new() возвращает адрес в куче ( heap ), и этому указателю вообще не обязательно
теперь на что-то указывать чтобы записать туда свое значение, так как роль адреса переменной теперь играет адрес возращенный new()?
Заранее спасибо за ответы.
Много текста - мало смысла...В Qt все визуальные элементы, которые принадлежат какому-то родительскому элементу (напр. кнопки на виджете), будут удалены когда вызовется деструктор самого родительского объекта.
Т.е. ниже приведенный код корректен:
QWidget *p = new QWIdget(0);
QLabel *lLabel = new QLabel(p);delete p;
>Много текста - мало смысла...А какой может быть смысл если это вопросы ... :)
>
>В Qt все визуальные элементы, которые принадлежат какому-то родительскому элементу (напр. кнопки
>на виджете), будут удалены когда вызовется деструктор самого родительского объекта.
>
>Т.е. ниже приведенный код корректен:
>
>QWidget *p = new QWIdget(0);
>QLabel *lLabel = new QLabel(p);
>
>delete p;Я знаю что этот код корректен. Вопрос другой.
Когда указатели идут через цикл, как потом освободить память.
if ( int i = 0; i < 25; ++i ) {
...
QLabel *mixDevLabel = new QLabel; // теряем адрес при каждом инкременте
...
}Ведь адрес то мы теряем...
Да и это не один вопрос был...
Потеряете вы адрес или нет зависит от тех трёх точек, в которых происходит использоваение вновь выделенного адреса.
Если вы его потом передаёте в контейнер как предидущем примере, то все адреса будут освобождены при удалении этого контейнера.
Советую почитать книжки про С/С++.
Про QT пока советую забыть, если конечно действительно есть желание во всем в конце концов разобраться, получить ответы на вопросы.
http://anatolix.naumen.ru/Books/CPlusPlus?v=13c3
>Советую почитать книжки про С/С++.
>Про QT пока советую забыть, если конечно действительно есть желание во всем
>в конце концов разобраться, получить ответы на вопросы.
>http://anatolix.naumen.ru/Books/CPlusPlus?v=13c3Не ужели так тяжело ответить на вопрос?
Спасибо, но Qt забывать не собираюсь.
>Не ужели так тяжело ответить на вопрос?
>Спасибо, но Qt забывать не собираюсь.
> Когда указатели идут через цикл, как потом освободить память.вам уже сказали, освобождайте любыми доступными способами.
std::vector<QLabel *> vptr;
if ( int i = 0; i < 25; ++i )
{
...
QLabel *mixDevLabel = new QLabel;
vptr.push_back(mixDevLabel);
...
}std::vector<QLabel *>::const_iterator it1 = vpt.begin();
std::vector<QLabel *>::const_iterator it2 = vpt.end();
for(; it1 != it2; ++it1) if(*it1) delete *it1;
>>Не ужели так тяжело ответить на вопрос?
>>Спасибо, но Qt забывать не собираюсь.
>> Когда указатели идут через цикл, как потом освободить память.2 andrey: Не согласен!!! Так делать не надо! Не в том смысле что это не работает, а в том что при нормальном создании QLabel он всегда ДОЛЖЕН помещаться в контейнер!
Поэтому как правильно заметил Андрей!!! все зависит от тех 3 точек! где и должно происходить помещение указателя QLabel в контейнер.
А следовательно, еще один вектор владеющий указателями не нужен! он будет повторно пытаться освобождать память которую будет освобожать родной объект-контейнер от Qt.
>Не ужели так тяжело ответить на вопрос?А какой смысл на него отвечать, если Вы не ориентируетесь в теме даже на уровне beginner ? Какая в этом ПРАКТИЧЕСКАЯ польза ? Это как учиться летать на самолете СРАЗУ на практике - не получилось, катапультируемся и летим на новом.
>Спасибо, но Qt забывать не собираюсь.
Да не за что. На самом деле ссылку, которую я дал сложно ПЕРЕоценить. Там собраны действительно ЛУЧШИЕ книги. А про QT это просто совет, начинать лучше с чего-то попроще.
>Доброго дня всем!
>
>И еще несколько вопросов на эту тему.
>
>1. Кто на практике знает, много ли программ под UNIX имеет утечку
>и на сколько она большая?я упал!
:-)>2. Есть ли программа для просмотра ( доступа ) памяти под UNIX?
>( Помню под винду была написана на Delphi )простите, доступа к чьей памяти?
>3. Средства для контроля утечки
Ну поскольку я не профессионал, пользуюсь mcheck, для моих задач хватает.
>
>Указатели:
>
>Как я понимаю нету способов узнать адрес самого указателя?Как то вы не правильно понимаете!!!
#include <iostream>
int main() {
int *p = new int;
*p = 5;
std::cout << "*p = "<< *p << std::endl;
std::cout << "p = " << p << std::endl;
//а вот и адресс указателя в памяти, я так понимаю это стек.
std::cout << "&p= " << &p << std::endl;
delete p;
}
>Далее...
>Вот такой кусок кода приведет к ошибке сегментирования:
>
> Qt *p;
> *p = 5;
>ну да вы догадались!!! Удивляюсь куда компилятор то смотрит!?!
Во первых в объект не того типа, а во вторых да!, по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресу>
> int *p = new int;
> *p = 5;
>А вот тут вы совершенно правы!
>Все нормально. Если я правильно понимаю, new() возвращает адрес в куче (
>heap ), и этому указателю вообще не обязательноА вот тут вы ошибаетесь, память выделена под инт, попытаетесь туда что нибудь "побольше" положить и уничтожите другие переменные в куче.
>по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресунеинициализированный - это совсем не 0x000000, это значит что может быть ВСЕ ЧТО УГОДНО :)
>>по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресу
>
>неинициализированный - это совсем не 0x000000, это значит что может быть ВСЕ
>ЧТО УГОДНО :)а ну да, просто очень часто там ноль. я щас проверил, когда эта переменна в стеке, там мусор какой то. а когда она глобальная и размещена в .bss там 0(ну навернаяка зависит от загрузчика ос).
>>>по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресу
>>
>>неинициализированный - это совсем не 0x000000, это значит что может быть ВСЕ
>>ЧТО УГОДНО :)
>
>а ну да, просто очень часто там ноль. я щас проверил, когда
>эта переменна в стеке, там мусор какой то. а когда она
>глобальная и размещена в .bss там 0(ну навернаяка зависит от загрузчика
>ос).Просто глобальные переменные всегда инициализируются нулями.
Автопеременные нет, поэтому там мусор.
>>Доброго дня всем!
>>
>>И еще несколько вопросов на эту тему.
>>
>>1. Кто на практике знает, много ли программ под UNIX имеет утечку
>>и на сколько она большая?
>
>я упал!
>:-)Я думал падают только приложения :))
>
>>2. Есть ли программа для просмотра ( доступа ) памяти под UNIX?
>>( Помню под винду была написана на Delphi )
>
>простите, доступа к чьей памяти?У меня на копме есть к примеру 1 гиг оперативки.
Можно просмотреть как-то ее содержимое? Или это невозможно?>[оверквотинг удален]
>
> std::cout << "*p = "<< *p << std::endl;
> std::cout << "p = " << p <<
>std::endl;
> //а вот и адресс указателя в
>памяти, я так понимаю это стек.
> std::cout << "&p= " << &p << std::endl;
>
> delete p;
>}Ступил. Перепутал с ссылкой.
>
>
>>Далее...
>>Вот такой кусок кода приведет к ошибке сегментирования:
>>
>> Qt *p;
>> *p = 5;
>>
>имелось в виду конечно int *p;
>[оверквотинг удален]
>>
>
>А вот тут вы совершенно правы!
>
>
>>Все нормально. Если я правильно понимаю, new() возвращает адрес в куче (
>>heap ), и этому указателю вообще не обязательно
>
>А вот тут вы ошибаетесь, память выделена под инт, попытаетесь туда что
>нибудь "побольше" положить и уничтожите другие переменные в куче.- вопрос был не об этом
- разве можно положить в int "побольше"? ИМХО компилятор не даст..
>>>1. Кто на практике знает, много ли программ под UNIX имеет утечку
>>>и на сколько она большая?
>>
>>я упал!
>>:-)
>
>Я думал падают только приложения :))Ок, 8 программ имеют утечку памяти, остальные нет.
Ну честно слово, где такую статистику то взять? =)>
>>
>>>2. Есть ли программа для просмотра ( доступа ) памяти под UNIX?
>>>( Помню под винду была написана на Delphi )
>>простите, доступа к чьей памяти?в линух смотрим в /proc/core =) Это вся память.
/proc/<pid>/mem вроде память процесса (не помню точно).
Разберетесь - мне расскажите =)>У меня на копме есть к примеру 1 гиг оперативки.
>Можно просмотреть как-то ее содержимое? Или это невозможно?Умеем в хексах править программы на лету? =)
>>> Qt *p;
>>> *p = 5;
>имелось в виду конечно int *p;Все равно нас ждет segfault =) память-то не выделена.
Объявлен указатель типа int в никуда.>- вопрос был не об этом
>- разве можно положить в int "побольше"? ИМХО компилятор не даст..легко, 95% программистов (включая меня =)) это могут. сишные преобразаования типов, всякие memcpy неправильно использованные и т.д. нам помогут.
Если серьезно, то возьмите качественные книжки по С и книжки по С++ внимательно почитайте. Хотя бы книги господ создателей этих языков (Керниган и Ричи, Страуструп). Вы путаетесь в довольно простых моментах в работе с указателями.
>[оверквотинг удален]
>>>>и на сколько она большая?
>>>
>>>я упал!
>>>:-)
>>
>>Я думал падают только приложения :))
>
>Ок, 8 программ имеют утечку памяти, остальные нет.
>Ну честно слово, где такую статистику то взять? =)
>Я имею ввиду такое:
Многие программы имеют утечку, но разработчики это не знают, или знают но не знают как выловть ее ( это очень трудно ), или к примеру opeтoffice дает утечку примерно в 5 Mb или что-то в том роде... То есть тот кто реально знает случаи утечки и насколько они были или есть большие...
Хочу знать на что мне расчитовать :))Не надо утрировать, я понимаю что статистики нигде нету, само собой.
>[оверквотинг удален]
>>>простите, доступа к чьей памяти?
>
>в линух смотрим в /proc/core =) Это вся память.
>/proc/<pid>/mem вроде память процесса (не помню точно).
>Разберетесь - мне расскажите =)
>
>>У меня на копме есть к примеру 1 гиг оперативки.
>>Можно просмотреть как-то ее содержимое? Или это невозможно?
>
>Умеем в хексах править программы на лету? =)Я разве говорил про править? Я говорил для просмотра... под виндой помню была. Названия не помню.. Давно было.
>
>>>> Qt *p;
>>>> *p = 5;
>>имелось в виду конечно int *p;
>
>Все равно нас ждет segfault =) память-то не выделена.
>Объявлен указатель типа int в никуда.Я знаю что будет segfault :))
Я ж сам про это писал :D
Имелось ввиду про то что перетупал тип.И разве указатель обявлен в никуда?!?
int *p;
std::cout << *p << std::endl; // значение которое хнатиться по адресу (мусор)
std::cout << p << std::endl; // адрес который храниться в указателе (мусор)
std::cout << &p << std::endl; // адрес самого указателя1474660693
0xb7f43206
0xbfa98770>[оверквотинг удален]
>>- вопрос был не об этом
>>- разве можно положить в int "побольше"? ИМХО компилятор не даст..
>
>легко, 95% программистов (включая меня =)) это могут. сишные преобразаования типов, всякие
>memcpy неправильно использованные и т.д. нам помогут.
>
>Если серьезно, то возьмите качественные книжки по С и книжки по С++
>внимательно почитайте. Хотя бы книги господ создателей этих языков (Керниган и
>Ричи, Страуструп). Вы путаетесь в довольно простых моментах в работе с
>указателями.Возьми,почитай... А я что знания в астрала беру?!? :))
> Я разве говорил про править? Я говорил для просмотра... под виндой помню была. Названия не помню.. Давно было.Можно тупой вопрос: зачем? Разве нет отладчика? (Если действительно не знаете, то отладчик называется gdb)
> std::cout << *p << std::endl; // значение которое хнатиться по адресу
>(мусор)
> std::cout << p << std::endl; // адрес который храниться в
>указателе (мусор)
> std::cout << &p << std::endl; // адрес самого указателя
>
>1474660693Это очень "повезло", что удалось прочитать значение по случайному адресу. Уж лучше бы не повезло и вы бы получили segfault. А так у вас может вдруг сложиться впечатление, что этот указатель рабочий только потому, что он указывает на кусок памяти вашей программы. А ведь это не обязательно сегмент данных. Не обязательно .bss. Может быть и куча, или даже код!
Против утечек памяти легче всего использовать готовые утилиты для их поиска и локализации: BoundsChecker ( ссыль не помню ), Deleaker ( http://deleaker.ru/ )