Как правильно объявлять и инициализировать (большой) массив двумерных объектов в C++?
Мне нужно создать большой двумерный массив объектов. Я читал некоторые связанные вопросы на этом сайте и другие, касающиеся multi_array, matrix, vector и т. Д., Но не смог собрать их вместе. Если вы рекомендуете использовать один из них, пожалуйста, переведите код ниже.
Некоторые соображения:
- Массив несколько большой (1300 х 1372).
- Я мог бы работать с более чем одним из них одновременно.
- Я должен передать его функции в какой-то момент.
- Скорость это большой фактор.
Два подхода, о которых я подумал:
Pixel pixelArray[1300][1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i][j].setOn(true);
...
}
}
а также
Pixel* pixelArray[1300][1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i][j] = new Pixel();
pixelArray[i][j]->setOn(true);
...
}
}
Какой правильный подход / синтаксис здесь?
Редактировать:
Несколько ответов предположили Pixel
маленький - я оставил подробности о Pixel
для удобства, но это не маленький / тривиальный. Он имеет ~20 членов-данных и ~16 функций-членов.
6 ответов
Ваш первый подход распределяет все по стеку, что в целом хорошо, но приводит к переполнению стека, когда вы пытаетесь выделить слишком много стека. В современных ОС ограничение обычно составляет около 8 мегабайт, поэтому размещение массивов из 1300 * 1372 элементов в стеке невозможно.
Ваш второй подход выделяет 1300 * 1372 элементов в куче, что является огромной нагрузкой для распределителя, который содержит несколько связанных списков с частями выделенной и свободной памяти. Также плохая идея, тем более что Pixel кажется довольно маленькой.
Что бы я сделал, это:
Pixel* pixelArray = new Pixel[1300 * 1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i * 1372 + j].setOn(true);
...
}
}
Таким образом, вы выделяете один большой кусок памяти в куче. Стек доволен, как и распределитель кучи.
Я не уверен, насколько сложен ваш тип данных Pixel, но, возможно, что-то подобное будет работать для вас?:
std:: fill (массив, массив +100, 42); // устанавливает каждое значение в массиве на 42
Ссылка: Инициализация нормального массива с одним значением по умолчанию
Если вы хотите передать это функции, я бы проголосовал против использования простых массивов. Рассматривать:
void doWork(Pixel array[][]);
Это не содержит никакой информации о размере. Вы можете передать информацию о размере через отдельные аргументы, но я бы предпочел использовать что-то вроде std::vector
Альтернативой является std::vector
Это в основном ваши варианты использования стандартной библиотеки. Правильным решением будет что-то вроде std::vector с двумя измерениями. Вспоминаются числовые библиотеки и библиотеки манипулирования изображениями, но классы матриц и изображений, скорее всего, ограничены примитивными типами данных в своих элементах.
РЕДАКТИРОВАТЬ: Забыл прояснить, что все выше, это только аргументы. В конце концов, ваш личный вкус и контекст должны быть приняты во внимание. Если вы сами в проекте, вектор плюс определенное и задокументированное соглашение об адресации должно быть достаточно хорошим. Но если вы в команде, и, вероятно, кто-то не примет во внимание документированное соглашение, каскадная структура вектор-вектор, вероятно, будет лучше, потому что утомительные части могут быть реализованы вспомогательными функциями.
Проверьте Универсальную библиотеку изображений Boost.
gray8_image_t pixelArray;
pixelArray.recreate(1300,1372);
for(gray8_image_t::iterator pIt = pixelArray.begin(); pIt != pixelArray.end(); pIt++) {
*pIt = 1;
}
Хотя я не обязательно делаю это структурой, это демонстрирует, как я буду подходить к хранению и доступу к данным. Если Pixel довольно большой, вы можете вместо этого использовать std::deque.
struct Pixel2D {
Pixel2D (size_t rsz_, size_t csz_) : data(rsz_*csz_), rsz(rsz_), csz(csz_) {
for (size_t r = 0; r < rsz; r++)
for (size_t c = 0; c < csz; c++)
at(r, c).setOn(true);
}
Pixel &at(size_t row, size_t col) {return data.at(row*csz+col);}
std::vector<Pixel> data;
size_t rsz;
size_t csz;
};
Моим личным предпочтением было бы использовать std::vector
typedef std::vector<Pixel> PixelRow;
typedef std::vector<PixelRow> PixelMatrix;
PixelMatrix pixelArray(1300, PixelRow(1372, Pixel(true)));
// ^^^^ ^^^^ ^^^^^^^^^^^
// Size 1 Size 2 default Value