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

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

Node *newNode;

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

delete newNode;

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

Ответ 1

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

newNode = new Node();

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

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

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

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

Ответ 2

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

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. Если вы не соглас >

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