Как работать вокруг очень большого 2-го массива в C++

В Java все находится в форме класса.

Если вы хотите использовать любой объект, тогда у вас есть две фазы:

  1. Объявить
  2. Инициализация

Пример:

  • Объявление: Object a;
  • Инициализация: a=new Object();

То же самое для концепции массива

  • Объявление: Item i[]=new Item[5];
  • Инициализация: i[0]=new Item();

Если вы не дают секцию инициализации, тогда возникает NullpointerException.

9
задан Bryan Denny 16 September 2008 в 19:56
поделиться

10 ответов

Вам нужны приблизительно 2,5 megs, поэтому просто использование "кучи" должно быть прекрасным. Вам не нужен вектор, если Вы не должны изменять размер его. Посмотрите C++ FAQ, Облегченный для примера использования "2D" массива "кучи".

int *array = new int[800*800];

(Не забывайте delete[] это, когда Вы сделаны.)

11
ответ дан 4 December 2019 в 07:05
поделиться

Пример Kevin хорош, однако:

std::vector<T> buffer[width * height];

Должен быть

std::vector<T> buffer;

При расширении его немного Вы могли, конечно, добавить перегрузки оператора вместо в () - функции:

const T &operator()(int x, int y) const
{
  return buffer[y * width + x];
}

и

T &operator()(int x, int y)
{
  return buffer[y * width + x];
}

Пример:

int main()
{
  Array2D<int, 800, 800> a;
  a(10, 10) = 50;
  std::cout << "A(10, 10)=" << a(10, 10) << std::endl;
  return 0;
}
4
ответ дан 4 December 2019 в 07:05
поделиться

Вы могли сделать вектор векторов, но это будет иметь немного служебными. Для z-буфера более типичный метод должен был бы создать массив размера 800*800=640000.

const int width = 800;
const int height = 800;
unsigned int* z_buffer = new unsigned int[width*height];

Затем получите доступ к пикселям следующим образом:

unsigned int z = z_buffer[y*width+x];
2
ответ дан 4 December 2019 в 07:05
поделиться

Каждое сообщение до сих пор оставляет управление памятью для программиста. Это может и должно избежаться. ReaperUnreal является штопкой близко к тому, что я сделал бы, кроме я буду использовать вектор, а не массив и также заставлять размеры обработать параметры по шаблону и изменить функции доступа - и о просто IMNSHO очищают вещи немного:

template <class T, size_t W, size_t H>
class Array2D
{
public:
    const int width = W;
    const int height = H;
    typedef typename T type;

    Array2D()
        : buffer(width*height)
    {
    }

    inline type& at(unsigned int x, unsigned int y)
    {
        return buffer[y*width + x];
    }

    inline const type& at(unsigned int x, unsigned int y) const
    {
        return buffer[y*width + x];
    }

private:
    std::vector<T> buffer;
};

Теперь можно выделить этот 2-D массив на стеке очень хорошо:

void foo()
{
    Array2D<int, 800, 800> zbuffer;

    // Do something with zbuffer...
}

Я надеюсь, что это помогает!

Править: Удаленная спецификация массива от Array2D::buffer. Благодаря Andreas для ловли этого!

10
ответ дан 4 December 2019 в 07:05
поделиться

Я мог бы создать единственный массив размера 800*800. Вероятно, более эффективно использовать единственное выделение как это, вместо того, чтобы выделить 800 отдельных векторов.

int *ary=new int[800*800];

Затем, вероятно, инкапсулируйте это в классе, который действовал как 2D массив.

class _2DArray
{
  public:
  int *operator[](const size_t &idx)
  {
    return &ary[idx*800];
  }
  const int *operator[](const size_t &idx) const
  {
    return &ary[idx*800];
  }
};

Абстракция, показанная здесь, имеет много дыр, например, что происходит, если Вы получаете доступ мимо конца "строки"? Книга "Эффективный C++" имеет довольно хорошее обсуждение записи хороших многомерных массивов в C++.

2
ответ дан 4 December 2019 в 07:05
поделиться

Одна вещь, которую можно сделать, изменить размер стека (если Вы действительно хотите массив на стеке) с VC флаг, чтобы сделать, это [/F] (http://msdn.microsoft.com/en-us/library/tdkhxaks (По сравнению с 80) .aspx).

Но решение, которое Вы, вероятно, хотите, состоит в том, чтобы поместить память в "кучу", а не на стеке, для которого необходимо использовать a vector из vectors.

Следующая строка объявляет a vector из 800 элементов каждый элемент является a vector из 800 ints и сохраняет Вас от управления памятью вручную.

std::vector<std::vector<int> > arr(800, std::vector<int>(800));

Отметьте пространство между этими двумя закрывающими угловыми скобками (> >) который требуется в порядке, снимают неоднозначность его от оператора права сдвига (который больше не будет необходим в C++ 0x).

1
ответ дан 4 December 2019 в 07:05
поделиться

Или Вы могли попробовать что-то как:

boost::shared_array<int> zbuffer(new int[width*height]);

Необходимо все еще смочь сделать это также:

++zbuffer[0];

Больше никакого беспокойства об управлении памятью, никакие пользовательские классы для заботы о, и легко бросить вокруг.

1
ответ дан 4 December 2019 в 07:05
поделиться

Существует C как способ сделать:

const int xwidth = 800;
const int ywidth = 800;
int* array = (int*) new int[xwidth * ywidth];
// Check array is not NULL here and handle the allocation error if it is
// Then do stuff with the array, such as zero initialize it
for(int x = 0; x < xwidth; ++x)
{
    for(int y = 0; y < ywidth; ++y)
    {
         array[y * xwidth + x] = 0;
    }
}
// Just use array[y * xwidth + x] when you want to access your class.

// When you're done with it, free the memory you allocated with
delete[] array;

Вы могли инкапсулировать y * xwidth + x в классе с легким добираются и метод установки (возможно с перегрузкой [] оператор, если Вы хотите начать входить в более усовершенствованный C++). Я рекомендовал бы добраться до этого медленно хотя, если Вы только запускаете с C++ и не начинаете создавать допускающие повторное использование полностью шаблоны классов для массивов n-размера, которые просто смутят Вас, когда Вы начнетесь.

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

Я нашел, что C++ облегченный FAQ был большим для получения информации, такой как это. В особенности Вашим вопросом отвечают:

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.16

1
ответ дан 4 December 2019 в 07:05
поделиться

Можно выделить массив на статическом устройстве хранения данных (в объеме файла или добавить static спецификатор в функциональном объеме), если Вам нужен только один экземпляр.

int array[800][800];

void fn()
{
    static int array[800][800];
}

Таким образом, это не перейдет к стеку, и не необходимо иметь дело с динамической памятью.

1
ответ дан 4 December 2019 в 07:05
поделиться

Ну, основываясь на том, что запущенный Niall Ryan, если производительность является проблемой, можно взять этот шаг вперед путем оптимизации математики и инкапсуляции этого в класс.

Таким образом, мы запустим с небольшого количества математики. Вспомните, что 800 может быть записан в полномочиях 2 как:

800 = 512 + 256 + 32 = 2^5 + 2^8 + 2^9

Таким образом, мы можем записать нашу функцию обращения как:

int index = y << 9 + y << 8 + y << 5 + x;

Таким образом, если мы инкапсулируем все в хороший класс, мы добираемся:

class ZBuffer
{
public:
    const int width = 800;
    const int height = 800;

    ZBuffer()
    {
        for(unsigned int i = 0, *pBuff = zbuff; i < width * height; i++, pBuff++)
            *pBuff = 0;
    }

    inline unsigned int getZAt(unsigned int x, unsigned int y)
    {
        return *(zbuff + y << 9 + y << 8 + y << 5 + x);
    }

    inline unsigned int setZAt(unsigned int x, unsigned int y, unsigned int z)
    {
        *(zbuff + y << 9 + y << 8 + y << 5 + x) = z;
    }
private:
    unsigned int zbuff[width * height];
};
-1
ответ дан 4 December 2019 в 07:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: