C++, выделение места в цикле for, возможная проверка утечки памяти

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

Node *newNode;

for (int i = 0; i < 10; i++)
{
    newNode = new Node();
}

delete newNode;

Так что, очевидно, код ничего не делает, но он помогает мне объяснить мой сценарий. Я выделяю память 10 раз и когда я удаляю указатель, оставляющий 9 сирот? Или я повторно использую одно и то же выделенное пространство и правильно удаляю сироту? Заранее спасибо!


person Xav    schedule 14.03.2013    source источник
comment
Вы можете использовать Valgrind для запуска вашей программы, чтобы увидеть, нет ли у вас утечек памяти.   -  person taocp    schedule 14.03.2013
comment
10 элементов, 1 удаление, 9 сирот.   -  person enhzflep    schedule 14.03.2013
comment
Вы делаете первое. Только последнее выделение будет правильно очищено. Остальные девять объектов осиротели.   -  person OldProgrammer    schedule 14.03.2013


Ответы (2)


Да, это утечка памяти. Когда вы делаете:

newNode = new Node();

Вы переопределяете указатель так, чтобы он указывал на вновь выделенную память, фактически теряя способ обращения к памяти, на которую ранее указывалось, чтобы удалить ее.

Поэтому, когда вы выходите из цикла, указатель newNode указывает на последнюю выделенную (десятую) память /Node. Когда вы delete newNode вы удаляете только эту память. У вас больше нет способа delete других.

Как указал Чжи Ван, вы можете использовать некоторую форму интеллектуального указателя (unique_ptr или shared_ptr в C++11, например). Эти интеллектуальные указатели в основном являются обертками для обычных указателей, которые имеют дополнительную семантику, предотвращающую подобную утечку. Если бы вы использовали один из них, память/объекты автоматически освобождались бы, когда они выходили за рамки (в этом случае по завершении текущей итерации цикла for).

Однако я не думаю, что в данном случае это решит вашу ситуацию. Я сомневаюсь, что вы захотите delete 10 объектов сразу после их создания. Скорее вы, вероятно, захотите хранить эти объекты в контейнере, таком как std::vector, или, по крайней мере, иметь массив указателей, указывающих на каждый из этих выделенных экземпляров. Таким образом, у вас будут объекты вокруг (что, я считаю, именно то, что вам нужно, поскольку вы вообще их строите), а также будет способ удалить их позже.

person Jorge Israel Peña    schedule 14.03.2013
comment
Точно, @ user1535978, не делайте так, используйте более умный указатель для хранения выделенной памяти. - person Zhi Wang; 14.03.2013
comment
Большое спасибо, в итоге я использовал массив указателей, которые я мог удалить сразу после последнего использования. Я ценю помощь. :) - person Xav; 19.03.2013

Да, в вашем коде происходит утечка памяти. Ваша первая догадка о поведении верна. Этот код

Node *newNode;

for (int i = 0; i < 10; i++)
{
    newNode = new Node();  // allocate memory 10 times in a loop...
}

delete newNode;            // ... but free the memory only once!

выделяет память 10 раз (оператор new внутри цикла for), но освобождает память, используемую только одним из этих объектов (оператор delete внизу). Естественно, это оставляет остальные 9 объектов бесхозными — память, которую они потребляют, по-прежнему выделена, но теперь у вас нет доступа к ней, чтобы освободить ее. Это, конечно, само определение утечки памяти.

Напротив, этот код

Node *newNode;

for (int i = 0; i < 10; i++)
{
    newNode = new Node();    // allocate memory 10 times in a loop
    delete newNode;          // ... and free the memory each time
}

не приводит к утечке памяти, потому что на каждый вызов new приходится один вызов delete. Это большое правило, которое вы должны помнить: если вы не сопоставите каждый вызов new с соответствующим вызовом delete, у вас будет утечка памяти.

Или, возможно, даже лучшее правило, когда вы работаете на C++, никогда не использовать необработанные указатели. Стандартная библиотека C++ предоставляет несколько отличных классов-оболочек, которые реализуют идиому RAII для указателей, которая гарантирует, что объекты, на которые указывают указатели, будут правильно уничтожены и, следовательно, память, которую они потребляют, будет освобождена. Начните свое исследование либо с вашей любимой книги по C++, либо с Википедия.

person Cody Gray    schedule 14.03.2013
comment
Я определенно не буду использовать необработанные указатели в будущем, но они выходят за рамки того, что мой профессор ожидает от этого задания. Спасибо за помощь. :) - person Xav; 19.03.2013
comment
Вам нужно удалить переменные, объявленные в циклах for? Я думал, что они автоматически удаляются в закрывающей скобке. - person CodyBugstein; 19.11.2013