C : как безопасно освободить выделенный в куче массив векторов?

#c #vector #memory-management #heap-memory #dynamic-memory-allocation

#c #вектор #управление памятью #куча-память #динамическое выделение памяти

Вопрос:

В настоящее время я работаю с кодом, который на данный момент требует от меня создания массива векторов (я новичок в C — если это абсолютно ужасная идея, я был бы очень признателен за обратную связь).

Допустим, я выделяю память в куче для своих векторов следующим образом:

 #include <iostream>
#include <vector>
#include <random>

int main() {
    typedef std::vector<double> doubleVec;
    long N = 1000;
    long M = 1000;

    doubleVec *array = new doubleVec[N];

    for (long i = 0; i < N; i  ) {
        doubleVec currentVec = array[i];
        currentVec.resize(M);
        for (long j = 0; j < M; j  )
            currentVec[j] = std::rand();
    }
    // ... do something with the data structure

   delete [] array;
}
  

Когда я сделал все, что мне нужно сделать с данными, как я должен безопасно освободить эту структуру данных?

ПРИМЕЧАНИЕ: в моем первоначальном сообщении были и другие ошибки, которые я сделал неправильно, и которые я не собирался делать предметом обсуждения (неинициализированные переменные, не измененные размеры векторов и т.д.). Я исправил это сейчас. Спасибо всем, что указали на это.

Комментарии:

1. Используйте интеллектуальные указатели, например: std::unique_ptr вместо необработанных указателей, но «точка» заключается в том, «зачем вам нужна куча указателей»?

2. И по какой причине вы не используете std::vector<std::vector<double>> for array ?

3. Вы создали его с помощью new[] ; вы уничтожаете его с помощью delete[] . Не переусердствуйте.

Ответ №1:

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

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

Как безопасно освободить выделенный в куче массив векторов?

Используя вектор вместо динамического массива вручную. В этом случае простым решением является использование вектора векторов.

Потенциально лучшим решением было бы выделить один плоский вектор из двойников размером 1000 * 1000, где элементы каждого «подвектора» следуют за другим. Для вычисления индекса вложенных векторов требуется немного простой математики, но в большинстве случаев это выполняется быстрее.


Другие примечания:

 typedef std::vector<double> doubleVec;
  

Избегайте запутывания программы, скрывая имена типов, подобные этому.

  for (long j; j < M; j  )
      ^^^^^^
  

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

Кроме того, вы забыли включить стандартные заголовки, которые определяют std::vector и std::rand .

Я получил ошибку seg

Смотрите Другой ответ, касающийся того, что вы фактически не добавляете какие-либо элементы к векторам, которые находятся в массиве. Это и неинициализированные переменные являются наиболее вероятной причиной вашего segfault в зависимости от того, что делает «сделать что-то».

Комментарии:

1. Какая альтернатива лучше? Должен ли я просто создать массив массивов или вектор векторов? (Я немного осознаю, что это глупый вопрос)

2. @Gromulus-Romulus Смотрите второй абзац.

3. Был бы вектор векторов лучше, потому что тогда мне не пришлось бы думать об указателях? Я мог бы просто передать по ссылке на любую функцию, которая будет его использовать?

4. Ошибка Seg теперь исправлена. Все это было из-за того, что я неправильно инициализировал переменные.

Ответ №2:

Проблема не в освобождении, а в распределении каждого вектора. Где в вашем коде вы используете M значение (кроме как при доступе к элементам)? В вашем коде есть другие проблемы, поэтому быстрое решение заключается в:

     for (long i; i < N; i  ) {
        doubleVec amp;currentVec = array[i];
        currentVec.resize(M);
        for (long j; j < M; j  )
            currentVec[j] = std::rand();
    }
  

Обратите особое внимание, что currentVec это ссылка: в противном случае никакие изменения не будут сохранены в array .

В любом случае, главный вопрос, который возникнет у всех: зачем вам нужен массив векторов?.. Вектор векторов — гораздо более элегантное решение.

Обновление: я пропустил тот факт, что вы забыли инициализировать оба i и j . В дополнение к совету по их инициализации я бы рекомендовал использовать auto ключевое слово, которое сделало бы невозможным оставить переменную неинициализированной:

     for (auto i=0UL; i < N; i  ) {
        doubleVec amp;currentVec = array[i];
        currentVec.resize(M);
        for (auto j=0UL; j < M; j  )
            currentVec[j] = std::rand();
    }
  

0UL означает ноль типа unsigned long.

Комментарии:

1. Потому что я допустил серьезную и непрерывную ошибку в суждении.