2011-02-01 5 views
2

Я создал этот 2D Qlist. Код «работает», но когда я рассматриваю немного более глубокий синтаксис, мне остается задаться вопросом, приводит ли этот код к утечке памяти.2d QList Memory Leak

Было бы здорово, если бы кто-то мог пролить свет на то, приводит ли этот код к утечке памяти или нет. Если это так, ПОЧЕМУ и как исправить?

Мои особые вопросы касаются вопросов, отмеченных как Q1, Q2, Q3, Q4 в комментариях кода.

Также, как я должен уничтожить некоторые строки из lszq2DList и в конечном итоге, как я должен уничтожить lszq2DList.

//The 2d data sructure. Each row will be a QStringList. 
QList<QStringList> lszq2DList; 

//The variable "emptyTempList" is a concern to me. 
//Q1:: Isn't "emptyTempList" just a pointer to some allocated place in memory? 
//If so, I imagine it points to some data structure allocated in memory. 
//Or does this not allocate anything? I have a feeling it does not. 
QStringList emptyTempList; //I use it in my scheme to make a 2D data struct. 

for(int i=0; i<3; i++){ 
    //Q2: Because I am in a loop and reusing the same pointer "emptyTempList", 
    //aren't i pointing to the same thing? 
    //If I think about this, each item in my Qlist (each row) should be 
    //pointing to the same place in memory. To whatever "emptyTempList" 
    //points to.  
    //Of course, this is not the case. What is really going on in line bellow? 
    lszq2DList += emptyTempList; //I'm no really pointing to anything am I? 

    QString szqTempString; //Q3: Gets trashed when out of scope? 
    for(int j=0; j<3; j++){ 
     szqTempString.clear(); 
     szqTempString = "jazz"; 

      //QString value gets copied into datastructure? 
     lszq2DList[i] += szqTempString; 
    } 
} 


QStringList emptyTempList2; 
emptyTempList2 += "blues"; 
emptyTempList2 += "blues"; 
emptyTempList2 += "blues"; 

//I'll add another row. 
lszq2DList += emptyTempList2; 
//Q4: lszq2DList[3] does not point to emptyTempList2, right? 
//Instead it copies all the strings 
//from to emptyTempList2 to lszq2DList[3], right? 
+3

Ваш размещенный код даже не имеет распределения памяти, как он может иметь какие-либо утечки? –

ответ

3

Я предлагаю проверить утечки памяти, используя что-то похожее на valgrind или другое.

Однако, когда память «утечки», это означает, что после использования эта память просто не освободилась, и весь доступ был удален. Это, по сути, означает, что имеется память, выделенная в куче, например, но ничто не имеет к ней доступа, так что это практически бесполезная память. Например, когда вы динамически выделяете память указателю с помощью «new», вы должны «удалить», чтобы освободить память. Приведу пример.

char * ptr = new char; 
ptr = NULL; // Memory leak 
delete ptr; // This is useless since it no longer points to the memory location 

Однако это совершенно действует

char * ptr = new char; 
delete ptr; 
ptr = NULL; 

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

Тем не менее, это не похоже, что ваш код будет иметь какие-либо утечки памяти в нем (ничего не динамически выделяется). Поскольку похоже, что все ваши переменные выделяются в стеке, система управляет этой памятью для вас - как только эти объекты выходят из области видимости (если она находится в main(), а затем, когда программа выходит), они будут выскользнуть из стека система. Это предполагает, однако, что QList не протекает.

EDIT

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

РЕДАКТИРОВАТЬ 2

В отношении использованием кучи против стека, использование стека каждый раз, когда это возможно. Чем меньше памяти вы должны управлять, тем лучше (и меньше подвержено ошибкам). Что касается второго вопроса, вы не используете указатели. Что вы делаете, это копирование значения из emptyTempList и не повторное использование его памяти (поскольку это не указатель). Вы должны использовать оператор & для извлечения адреса памяти из вашего объекта, так как, опять же, это не указатель.

Надеюсь, это поможет!

С уважением,
Dennis M.

+0

I c, спасибо. Я все еще запутался в Q2 :: в моем исходном коде. Вот что стало причиной моей путаницы. Сказав это, ваш ответ заставляет меня спросить, должен ли я использовать новый в приведенном выше примере, если бы я хранил много информации (например, сканирование файловой системы). То есть, я с большей вероятностью исчерпаю место в стеке, и поэтому вместо этого я должен использовать кучу? – user440297

+0

Я добавил немного ответа, надеюсь, что это поможет! – RageD

+0

Да, это помогает, спасибо. Однако, поскольку «emptyTempList» фактически не содержит данных, он копирует только его тип. В этом есть смысл. Неправильно? Я прихожу из Java, и эти вещи скрыты, поэтому мне никогда не приходилось думать о подкреплениях такого синтаксиса. Но, как указывает Катрина, кажется, что на самом деле это не действительно копирование по значению в традиционном смысле C-ASNI , На самом деле, похоже, мы имеем дело только с копированием адресов указателей ... поскольку я был заинтересован в комментариях к коду. Таким образом, вопрос в том, можно ли притворяться, что это копия по стоимости даже в приложениях с резьбой, хотя на самом деле это не так? – user440297

4

QList, QStringList и QString все "неявное совместное использование", которое в основном означает "копию на записи". Например:

QStringList someFunction() { 
    QStringList list; 
    QString str("Hello World!"); 

    for(int x = 0;x < 100; ++x) { 
     list << str; 
    } 

    QStringList list2 = list; 
    QStringList list3 = list; 
    QStringList list4 = list; 

    return list4; 
} 

QStringList list5 = someFunction(); 

В конце концов, у вас все еще есть строка «Hello World!». в памяти один раз. Вы можете узнать больше об этом Here. Как правило, с классами Qt «объекты, которые наследуют от QObject, переходят в кучу, иначе они идут в стек». Есть исключения, но очень мало и неявно разделяемые классы всегда должны идти в стек.

+0

Спасибо, отличный пост. Поскольку только указатель на данные передается по ссылке ur, Qt doc не говорит о нем, но могу ли я предположить, что в примере ur возвращенный «list4» является TRUE копией по значению, потому что иначе, когда функция заканчивается, мы бы перенастроить недействительный ref, поскольку из элементов сферы в func будет уничтожен. Qt doc говорит, когда вы «пишете», он делает глубокую копию. В документе Qt не ясно, когда вещи глубоко скопированы. Скажете ли вы, что безопасно притворяться, что Qt не выполняет «неявное совместное использование» в ситуациях, когда синтаксис подразумевает операцию копирования по значению и что эта схема является потокобезопасной? – user440297

+0

@ user440297: «return list4» создает копию QStringList, копируя сам список и увеличивая количество ссылок на неявно разделяемые внутренние элементы (copy-on-write). ref count == 2. Затем, когда область действия оставлена, «list4» разрушается, уменьшая ref. счет и оставить вас с возвращенной копией. ref count == 1. Внутренние элементы не копируются вообще, поэтому это дешевая операция. –

+0

@ user440297 в основном глубокая копия создается только в любое время, когда вы вызываете метод non-const для класса. –