Вызывает ли двойной вызов new [] дважды для одного и того же указателя без промежуточного вызова delete [] утечка памяти? - PullRequest
1 голос
/ 02 апреля 2012

Я слышал, что вы обычно должны "удалять" всякий раз, когда вы используете "new", но когда я запускаю простую тестовую программу (ниже), кажется, не имеет значения, какие числа я ставлю для arraySize или numLoops,Это вызывает утечку памяти?

#include <iostream>

int main()
{
    double *array;
    const int arraySize = 100000;
    const int numLoops = 100000;

    for (int i = 0; i < numLoops; i++)
    {
        // do I need to call "delete [] array;" here?
        array = new double[arraySize];
    }

    int x;
    std::cin >> x; // pause the program to view memory consumption

    delete [] array;

    return 0;
}

Ответы [ 6 ]

9 голосов
/ 02 апреля 2012

Нет, этого недостаточно.

Каждый раз, когда вы звоните new или new[], часть памяти выделяется, и вам дается адрес этой памяти (для возможности ее использования). Каждый кусок памяти должен в конечном итоге быть delete d (или delete[] d).

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

4 голосов
/ 02 апреля 2012

Это помогает правильно понять, что вы на самом деле делаете .

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

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

2 голосов
/ 02 апреля 2012

Да. Вы не вызываете new для указателя, вы вызываете new, и он возвращает указатель на выделенную память. Вы несете ответственность за удержание этого указателя и его удаление. Если вы перезаписываете это значение, то есть утечка.

1 голос
/ 02 апреля 2012

Два вопроса, два ответа.

Вопрос первый: вызывает ли вызов new [] дважды для одного и того же указателя без вызова delete [] между ними, вызывает утечку памяти?

Ответ один: не всегда, но в 99% случаев да. Приведенный ниже код дважды вызывает new с указателем на массив, но в первый раз он назначает адрес выделенной памяти для array2, а во второй раз он сохраняет этот адрес для себя. Можно удалить оба массива в этом сценарии.

#include <iostream>

int main()
{
    double *array;
    double *array2;
    const int arraySize = 100000;

    for (int i = 0; i < 2; i++)
    {
        // do I need to call "delete [] array;" here?
        array = new double[arraySize];
        if(i == 0)
        {
            array2 = array;
        }
    }

    int x;
    std::cin >> x; // pause the program to view memory consumption

    delete [] array;
    delete [] array2;

    return 0;
}

Вопрос второй: достаточно ли использования delete []?

Ответ второй: нет, потому что вызов delete влияет только на адрес, на который указывает указатель, который вы ему дали. Когда вы перезаписали указатель в вашем примере, он удалит последний выделенный раздел памяти

1 голос
/ 02 апреля 2012

Да.К счастью, есть лучший способ - вместо непосредственного выделения памяти используйте std::vector:

#include <iostream>
#include <vector>

int main()
{
    double *array;
    const int arraySize = 100000;
    const int numLoops = 100000;

    for (int i = 0; i < numLoops; i++)
    {
       std::vector<double> array(arraySize);
       // use it just like a normal array
    }

    int x;
    std::cin >> x; // pause the program to view memory consumption
    return 0;
}

. vector будет уничтожаться (и память, которой он управляет) на каждой итерации цикла.

Как правило, вы не должны использовать new, если вам действительно не нужно.Я бы даже сказал, что никогда не нужно (или даже нет веской причины) использовать массив в виде new.

1 голос
/ 02 апреля 2012

Всякий раз, когда вы new (или new[]) запоминаете, вы должны delete (или delete[]), или оно будет вытекать.

Каждый раз, когда вы звоните новому, выget возвращает указатель на выделенный объект кучи, если операция new выполнена успешно.Если указатель на эту память выходит из области видимости или переназначается (то есть, что вы здесь делаете), то вы не сможете удалить память позже.

В вашем примере кода будет уничтожена только последняя выделенная память.Вы можете использовать что-то вроде проводника процессов или даже диспетчера задач для проверки утечек памяти.

...