C ++, удаление динамических массивов, определенных в функциях / итерационных процессах - PullRequest
1 голос
/ 12 июня 2019

Я работаю над назначением, которое включает обновление размера динамического массива для хранения повторяющихся входных данных со значением -1, обозначающим конец ввода. Когда я использую этот код:

    bool end = false;
    int curr;
    int n = 0;
    int* currArr = new int[n];
    int* temp = NULL;
    while (end == false) {  
        cin >> curr;
        if (curr == -1) {
            end = true;
        }
        else {
            n++;
            int* temp = new int[n];
            temp = currArr;
            temp[n - 1] = curr;
            currArr = temp;
        }
    }
    delete[] currArr;
    delete[] temp;

Определил ли я адрес памяти для temp, изменил то, что хранится по этому адресу во время каждой итерации, а затем аккуратно удалил содержимое этого адреса в конце?

Или я выделяю новый динамический массив во время каждой итерации, удаляя только массив, определенный в последней итерации, и пропуская остальные? Если так, как бы мне этого избежать?

Точно так же, если я определю динамический массив внутри функции следующим образом:

int* fxn(int size) {
    int* x = new int[size];
    return &x[0];
}

int main() {
    int* y = fxn(size);
    delete[] y;
    return 0;
}

Насколько я понимаю, удаление y приведет к удалению массива, поскольку y указывает на тот же адрес, на который указывал x в функции. Если бы fxn была функцией void, то x нужно было бы удалить в пределах fxn, потому что fxn не выводил бы какую-либо информацию на главную страницу, с помощью которой можно найти x.

Правильно ли я понимаю?

Спасибо!

Ответы [ 2 ]

1 голос
/ 12 июня 2019
int* temp = new int[n];

Это выделяет новый массив int в динамической области, назначая выделенный массив temp. Сразу после этого:

temp = currArr;

Принимает вновь выделенный массив temp и немедленно перезаписывает этот указатель существующим указателем currArr. Недавно выделенная память просочилась, и когда все и сказано и сделано, и temp, и currArr теперь являются одним и тем же значением указателя (второе назначение, двумя строками позже, не меняет этого, уже слишком поздно) .

delete[] currArr;
delete[] temp;

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

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

Я определяю адрес памяти для temp, меняя то, что хранится в этот адрес во время каждой итерации, а затем аккуратно удаляя содержимое этого адреса в конце?

Нет, вы теряете память, портите память, вызываете неопределенное поведение и, скорее всего, происходит сбой.

Вам необходимо исправить первоначальное распределение, чтобы оно не перекрывалось, и delete предыдущий буфер (currArray) сразу после выделения нового (temp), а затем, наконец, назначить temp до currArray (после копирования его содержимого).

1 голос
/ 12 июня 2019

Каждый раз, когда вы выделяете память и назначаете свой предыдущий выделенный указатель для вновь выделенной памяти, вы должны удалить предыдущий.В противном случае это приводит к утечке памяти.В вашем случае curArr продолжает указывать на новый адрес в цикле, но предыдущий никогда не удаляется.Тогда ваше удаление как curArr, так и temp завершится сбоем, потому что они указывают на одно и то же место, поэтому вы дважды удаляете один и тот же указатель.И предоставив temp к curArray после его выделения, вы просто снова потеряли вновь выделенный указатель.Таким образом, код представляет собой гигантский беспорядок, полный утечек и сбоев.Вы также изначально выделяете память размером 0, что является неопределенным поведением.


#include <iostream>
#include <memory>
using namespace std;

int main(){
    bool end = false;
    int curr;
    int n = 1;
    int* currArr = new int[n];
    while (end == false) {
        cin >> curr;
        if (curr == -1) {
            end = true;
        }
        else {
            currArr[n - 1] = curr;
            int* temp = new int[n+1];
            memcpy(temp, currArr, n*sizeof(int));
            delete[] currArr;
            currArr = temp;
            ++n;
        }
    }
    for(int index = 0; index < n-1; ++index){
        std::cout << currArr[index]<< std::endl;
    }
    delete[] currArr;

}

Я избавился от избыточности в вашем коде и устранил утечки.Код изначально выделит память размером n = 1.Тогда все, что пользователь вводит в curr, будет помещено в индекс n-1.Затем новая память будет выделена с использованием временного размера n + 1.Предыдущая память из curArr будет скопирована во вновь выделенную область.Предыдущая область curArr будет удалена, а указатель будет присвоен новой области.

И да.Ваше понимание вашего второго вопроса верно.

...