Удаляют p, где p является указателем для выстраивания всегда утечки памяти?

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

Я записал эту крошечную программу и скомпилировал ее с Visual Studio 2008, работающий на Windows XP:

#include "stdafx.h"
#include "Windows.h"

const unsigned long BLOCK_SIZE = 1024*100000;
int _tmain()
{
    for (unsigned int i =0; i < 1024*1000; i++)
    {
        int* p = new  int[1024*100000];
        for (int j =0;j<BLOCK_SIZE;j++) p[j]= j % 2;
        Sleep(1000);
        delete p;
    }
}

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

Я изменил свою тестовую программу для выделения не массива типа примитива:

#include "stdafx.h"
#include "Windows.h"


struct aStruct
{
    aStruct() : i(1), j(0) {}

    int i;
    char j;
} NonePrimitive;

const unsigned long BLOCK_SIZE = 1024*100000;
int _tmain()
{
    for (unsigned int i =0; i < 1024*100000; i++)
    {
        aStruct* p = new  aStruct[1024*100000];
        Sleep(1000);
        delete p;

    }
}

после выполнения для в течение 10 минут не было никакого значимого увеличения памяти

Я скомпилировал проект с предупреждением уровня 4 и не получил предупреждений.

действительно ли возможно, что время выполнения Visual Studio отслеживает выделенные типы объектов, таким образом, там не отличается между delete и delete[] в той среде?

7
задан Eli 9 March 2010 в 13:02
поделиться

8 ответов

delete p, где p — массив, называется неопределенным поведением.

В частности, когда вы выделяете массив необработанных типов данных (ints), компилятору не нужно много работать, поэтому он превращает его в простой malloc(), поэтому удаление p, вероятно, будет работать.

delete p не удастся, как правило, когда:

  • p был сложным типом данных - удалить p; не будет знать, как вызывать отдельных деструкторов.
  • "пользователь" перегружает оператора new[] и удаляет[], чтобы использовать кучу, другую по сравнению с обычной кучей.
  • среда выполнения отладки перегружает оператор new[] и delete[], чтобы добавить дополнительную информацию об отслеживании массива.
  • компилятор решает, что ему необходимо хранить дополнительную информацию RTTI вместе с объектом, который удаляет p; не поймет, но удалите []p; воля.
19
ответ дан 6 December 2019 в 04:51
поделиться

Использование delete с [] указывает компилятору вызывать деструктор для каждого элемента массива. Не использование delete [] может вызвать утечку памяти, если он используется в массиве объектов, которые используют динамическое распределение памяти, как показано ниже :

class AClass
{
public:
    AClass()
    {
        aString = new char[100];
    }
    ~AClass()
    {
        delete [] aString;
    }
private:
    const char *aString;
};

int main()
{
    AClass * p = new  AClass[1000];
    delete p; // wrong
    return 0;
}
1
ответ дан 6 December 2019 в 04:51
поделиться

Это называется неопределенное поведение ; это может сработать, но вы не знаете почему, поэтому не стоит его придерживаться.

Я не думаю, что Visual Studio отслеживает, как вы распределяли объекты, в виде массивов или простых объектов, и волшебным образом добавляет [] к вашему удалению. Вероятно, он компилирует delete p; в тот же код, как если бы вы разместили с помощью p = new int , и, как я уже сказал, по какой-то причине он работает. Но вы не знаете почему.

3
ответ дан 6 December 2019 в 04:51
поделиться

Нет, это неопределенное поведение. Не делайте этого - используйте delete[].

В VC++ 7 to 9 он работает , когда рассматриваемый тип имеет тривиальный деструктор, но он может перестать работать на более новых версиях - обычные вещи с неопределенным поведением. Не делайте этого в любом случае.

17
ответ дан 6 December 2019 в 04:51
поделиться

нет, вы должны использовать delete[] при работе с массивами

2
ответ дан 6 December 2019 в 04:51
поделиться

Простое использование delete не вызовет деструкторы объектов в массиве. Хотя он , возможно, будет работать так, как задумано, он не определен, поскольку есть некоторые различия в том, как именно они работают. Так что вы не должны использовать его даже для встроенных типов .

2
ответ дан 6 December 2019 в 04:51
поделиться

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

Более соответствующий стандартам ответ - это неопределенное поведение. Компилятор, например, имеет полное право использовать пулы памяти для массивов, отличные от пулов памяти для элементов, не являющихся массивами. Выполнение нового одного способа, а удаление другого может привести к повреждению кучи.

Ваш компилятор может гарантировать, что стандарт этого не делает, но первая проблема остается. Для элементов POD, которые не владеют дополнительной памятью (или ресурсами, такими как дескрипторы файлов), все может быть в порядке.

Даже если это безопасно для вашего компилятора и элементов данных, все равно не делайте этого - это также вводит в заблуждение всех, кто пытается прочитать ваш код.

3
ответ дан 6 December 2019 в 04:51
поделиться

Причина, по-видимому, не в утечке памяти, потому что удаление обычно основано на свободном состоянии, которое уже знает, сколько памяти необходимо освободить. Однако часть c ++ вряд ли удастся правильно очистить. Готов поспорить, что вызывается только деструктор первого объекта.

1
ответ дан 6 December 2019 в 04:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: