URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 7002
[ Назад ]

Исходное сообщение
"C++ Утечка памяти, указатели"

Отправлено siegerstein , 04-Дек-07 15:57 
Доброго дня всем!

Есть вопрос по поводу утечки памяти ( 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()?
    
Заранее спасибо за ответы.


Содержание

Сообщения в этом обсуждении
"C++ Утечка памяти, указатели"
Отправлено Hordi , 04-Дек-07 16:50 
Много текста - мало смысла...

В Qt все визуальные элементы, которые принадлежат какому-то родительскому элементу (напр. кнопки на виджете), будут удалены когда вызовется деструктор самого родительского объекта.

Т.е. ниже приведенный код корректен:

QWidget *p = new QWIdget(0);
QLabel *lLabel = new QLabel(p);

delete p;



"C++ Утечка памяти, указатели"
Отправлено siegerstein , 04-Дек-07 19:08 
>Много текста - мало смысла...

А какой может быть смысл если это вопросы ... :)

>
>В Qt все визуальные элементы, которые принадлежат какому-то родительскому элементу (напр. кнопки
>на виджете), будут удалены когда вызовется деструктор самого родительского объекта.
>
>Т.е. ниже приведенный код корректен:
>
>QWidget *p = new QWIdget(0);
>QLabel *lLabel = new QLabel(p);
>
>delete p;

Я знаю что этот код корректен. Вопрос другой.

Когда указатели идут через цикл, как потом освободить память.

if ( int i = 0; i < 25; ++i ) {
   ...
   QLabel *mixDevLabel = new QLabel; // теряем адрес при каждом инкременте
   ...
   }

Ведь адрес то мы теряем...

Да и это не один вопрос был...



"C++ Утечка памяти, указатели"
Отправлено Андрей , 04-Дек-07 21:32 
Потеряете вы адрес или нет зависит от тех трёх точек, в которых происходит использоваение вновь выделенного адреса.
Если вы его потом передаёте в контейнер как предидущем примере, то все адреса будут освобождены при удалении этого контейнера.

"C++ Утечка памяти, указатели"
Отправлено tosha , 04-Дек-07 20:10 
Советую почитать книжки про С/С++.
Про QT пока советую забыть, если конечно действительно есть желание во всем в конце концов разобраться, получить ответы на вопросы.
http://anatolix.naumen.ru/Books/CPlusPlus?v=13c3

"C++ Утечка памяти, указатели"
Отправлено siegerstein , 04-Дек-07 20:25 
>Советую почитать книжки про С/С++.
>Про QT пока советую забыть, если конечно действительно есть желание во всем
>в конце концов разобраться, получить ответы на вопросы.
>http://anatolix.naumen.ru/Books/CPlusPlus?v=13c3

Не ужели так тяжело ответить на вопрос?
Спасибо, но Qt забывать не собираюсь.


"C++ Утечка памяти, указатели"
Отправлено andrey , 05-Дек-07 10:31 
>Не ужели так тяжело ответить на вопрос?
>Спасибо, но 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;


"C++ Утечка памяти, указатели"
Отправлено NuINu , 05-Дек-07 14:42 
>>Не ужели так тяжело ответить на вопрос?
>>Спасибо, но Qt забывать не собираюсь.
>> Когда указатели идут через цикл, как потом освободить память.

2 andrey: Не согласен!!! Так делать не надо! Не в том смысле что это не работает, а в том что при нормальном создании QLabel он всегда ДОЛЖЕН помещаться в контейнер!
Поэтому как правильно заметил Андрей!!! все зависит от тех 3 точек! где и должно происходить помещение указателя QLabel в контейнер.
А следовательно, еще один вектор владеющий указателями не нужен! он будет повторно пытаться освобождать память которую будет освобожать родной объект-контейнер от Qt.


"C++ Утечка памяти, указатели"
Отправлено tosha , 06-Дек-07 21:49 
>Не ужели так тяжело ответить на вопрос?

А какой смысл на него отвечать, если Вы не ориентируетесь в теме даже на уровне beginner ? Какая в этом ПРАКТИЧЕСКАЯ польза ? Это как учиться летать на самолете СРАЗУ на практике - не получилось, катапультируемся и летим на новом.

>Спасибо, но Qt забывать не собираюсь.

Да не за что. На самом деле ссылку, которую я дал сложно ПЕРЕоценить. Там собраны действительно ЛУЧШИЕ книги. А про QT это просто совет, начинать лучше с чего-то попроще.


"C++ Утечка памяти, указатели"
Отправлено NuINu , 05-Дек-07 15:03 
>Доброго дня всем!
>
>И еще несколько вопросов на эту тему.
>
>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 ), и этому указателю вообще не обязательно

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


"C++ Утечка памяти, указатели"
Отправлено Hordi , 05-Дек-07 15:47 
>по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресу

неинициализированный - это совсем не 0x000000, это значит что может быть ВСЕ ЧТО УГОДНО :)


"C++ Утечка памяти, указатели"
Отправлено NuINu , 05-Дек-07 16:20 
>>по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресу
>
>неинициализированный - это совсем не 0x000000, это значит что может быть ВСЕ
>ЧТО УГОДНО :)

а ну да, просто очень часто там ноль. я щас проверил, когда эта переменна в стеке, там мусор какой то. а когда она глобальная и размещена в .bss там 0(ну навернаяка зависит от загрузчика ос).



"C++ Утечка памяти, указатели"
Отправлено vic , 05-Дек-07 19:41 
>>>по неинициализированному(совершенно левому, т.е по адресу 0x000000) адресу
>>
>>неинициализированный - это совсем не 0x000000, это значит что может быть ВСЕ
>>ЧТО УГОДНО :)
>
>а ну да, просто очень часто там ноль. я щас проверил, когда
>эта переменна в стеке, там мусор какой то. а когда она
>глобальная и размещена в .bss там 0(ну навернаяка зависит от загрузчика
>ос).

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


"C++ Утечка памяти, указатели"
Отправлено siegerstein , 05-Дек-07 18:15 
>>Доброго дня всем!
>>
>>И еще несколько вопросов на эту тему.
>>
>>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 "побольше"? ИМХО компилятор не даст..


"C++ Утечка памяти, указатели"
Отправлено vic , 05-Дек-07 19:56 
>>>1. Кто на практике знает, много ли программ под UNIX имеет утечку
>>>и на сколько она большая?
>>
>>я упал!
>>:-)
>
>Я думал падают только приложения :))

Ок, 8 программ имеют утечку памяти, остальные нет.
Ну честно слово, где такую статистику то взять? =)

>
>>
>>>2. Есть ли программа для просмотра ( доступа ) памяти под UNIX?
>>>( Помню под винду была написана на Delphi )
>>простите, доступа к чьей памяти?

в линух смотрим в /proc/core =) Это вся память.
/proc/<pid>/mem вроде память процесса (не помню точно).
Разберетесь - мне расскажите =)

>У меня на копме есть к примеру 1 гиг оперативки.
>Можно просмотреть как-то ее содержимое? Или это невозможно?

Умеем в хексах править программы на лету? =)

>>>   Qt *p;
>>>   *p = 5;
>имелось в виду конечно int *p;

Все равно нас ждет segfault =) память-то не выделена.
Объявлен указатель типа int в никуда.

>- вопрос был не об этом
>- разве можно положить в int "побольше"? ИМХО компилятор не даст..

легко, 95% программистов (включая меня =)) это могут. сишные преобразаования типов, всякие memcpy неправильно использованные и т.д. нам помогут.

Если серьезно, то возьмите качественные книжки по С и книжки по С++ внимательно почитайте. Хотя бы книги господ создателей этих языков (Керниган и Ричи, Страуструп). Вы путаетесь в довольно простых моментах в работе с указателями.


"C++ Утечка памяти, указатели"
Отправлено siegerstein , 06-Дек-07 00:37 
>[оверквотинг удален]
>>>>и на сколько она большая?
>>>
>>>я упал!
>>>:-)
>>
>>Я думал падают только приложения :))
>
>Ок, 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 неправильно использованные и т.д. нам помогут.
>
>Если серьезно, то возьмите качественные книжки по С и книжки по С++
>внимательно почитайте. Хотя бы книги господ создателей этих языков (Керниган и
>Ричи, Страуструп). Вы путаетесь в довольно простых моментах в работе с
>указателями.

Возьми,почитай... А я что знания в астрала беру?!? :))


"C++ Утечка памяти, указатели"
Отправлено anonymous , 06-Дек-07 05:33 
> Я разве говорил про править? Я говорил для просмотра... под виндой помню была. Названия не помню.. Давно было.

Можно тупой вопрос: зачем?  Разве нет отладчика?  (Если действительно не знаете, то отладчик называется gdb)

> std::cout << *p << std::endl; // значение которое хнатиться по адресу
>(мусор)
> std::cout << p << std::endl;  // адрес который храниться в
>указателе (мусор)
> std::cout << &p << std::endl; // адрес самого указателя
>
>1474660693

Это очень "повезло", что удалось прочитать значение по случайному адресу.  Уж лучше бы не повезло и вы бы получили segfault.  А так у вас может вдруг сложиться впечатление, что этот указатель рабочий только потому, что он указывает на кусок памяти вашей программы.  А ведь это не обязательно сегмент данных.  Не обязательно .bss.  Может быть и куча, или даже код!


"C++ Утечка памяти, указатели"
Отправлено Лепс , 15-Июл-10 09:12 
Против утечек памяти легче всего использовать готовые утилиты для их поиска и локализации: BoundsChecker ( ссыль не помню ), Deleaker ( http://deleaker.ru/ )