#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>>
forarray
?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. Потому что я допустил серьезную и непрерывную ошибку в суждении.