Pregunta

Necesito crear un 2D int matriz de tamaño 800x800.Pero al hacerlo se crea un desbordamiento de pila (ja, ja).

Soy nuevo en C++, por lo que debo de hacer algo como un vector de vectores?Y sólo sintetizan la matriz 2d en una clase?

Específicamente, esta matriz es mi zbuffer en un programa de gráficos.Necesito almacenar un valor de z para cada pixel de la pantalla (de ahí el gran tamaño de 800x800).

Gracias!

¿Fue útil?

Solución

Se necesita alrededor de 2,5 megas, así que el uso de la pila debe estar bien.Usted no necesita un vector a menos que usted necesita para cambiar su tamaño.Ver C++ FAQ Lite para un ejemplo de uso de "2D" el montón de la matriz.

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

(No olvide delete[] cuando usted está listo).

Otros consejos

Cada post que hasta el momento deja la gestión de la memoria para el programador.Esto puede y debe ser evitado.ReaperUnreal está muy cerca de lo que me gustaría hacer, excepto que haría uso de un vector en lugar de una matriz y también hacer que las dimensiones de los parámetros de la plantilla y cambiar las funciones de acceso-y oh sólo IMNSHO limpiar un poco las cosas:

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;
};

Ahora usted puede asignar este 2-D de la matriz en la pila bien:

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

    // Do something with zbuffer...
}

Espero que esto ayude!

EDITAR:Eliminado de la matriz de especificación de Array2D::buffer.Gracias a Andreas para la captura de ese!

Kevin ejemplo es buena, sin embargo:

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

Debe ser

std::vector<T> buffer;

La expansión es un poco usted podría, por supuesto, agregar el operador sobrecargas en lugar de la a()-funciones:

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

y

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

Ejemplo:

int main()
{
  Array2D<int, 800, 800> a;
  a(10, 10) = 50;
  std::cout << "A(10, 10)=" << a(10, 10) << std::endl;
  return 0;
}

Usted podría hacer un vector de vectores, pero que tendría alguna sobrecarga.Para un z-buffer, el método más habitual sería la creación de una matriz de tamaño 800*800=640000.

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

A continuación, tener acceso a los píxeles de la siguiente manera:

unsigned int z = z_buffer[y*width+x];

Yo podría crear una sola dimensión de la matriz de 800*800.Es probablemente más eficaz el uso de una única asignación como este, en lugar de la asignación de 800 independiente de vectores.

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

Entonces, probablemente encapsular que en una clase en la que actuó como una matriz 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];
  }
};

La abstracción que se muestra aquí tiene un montón de agujeros, e.g, ¿qué sucede si el acceso fuera más allá del final de una "fila"?El libro "la eficacia de C++" tiene una muy buena explicación de la elaboración de un buen múltiples dimensiones de las matrices en C++.

Una cosa que puedes hacer es cambiar el tamaño de la pila (si usted realmente quiere la matriz en la pila) con VC la bandera para ello es [/F](http://msdn.microsoft.com/en-us/library/tdkhxaks(VS.80).aspx).

Pero la solución que usted probablemente desea es poner la memoria en el montón en lugar de en la pila, para que usted debe utilizar un vector de vectors.

La siguiente línea declara una vector de 800 elementos, cada elemento es un vector de 800 ints y le salva de la gestión de la memoria de forma manual.

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

Nota: el espacio entre los dos el cierre de corchetes angulares (> >) que se requiere a fin de eliminar la ambigüedad que a partir del cambio a la derecha del operador (que ya no será necesaria en C++0x).

O usted podría intentar algo como:

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

Usted debe ser capaz de hacer esto:

++zbuffer[0];

No más preocupaciones acerca de la administración de la memoria, no hay clases personalizadas para tomar cuidado de, y es fácil tirar todo.

No C como forma de hacer:

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;

Usted podría encapsular el y * xwidth + x dentro de una clase con un fácil métodos get y set (posiblemente con la sobrecarga de la [] operador si desea empezar a meterse en más avanzados de C++).Yo recomiendo entrar a este lentamente, aunque si estás empezando con C++ y no empezar a crear re-utilizable totalmente plantillas de clase para n-matrices de dimensión que se acaba de confundir cuando estás empezando.

Tan pronto como usted entrar en gráficos de trabajo que usted puede encontrar que la sobrecarga de tener la clase extra llamadas pueden ralentizar el código.Sin embargo no te preocupes por esto hasta que su aplicación no es lo suficientemente rápida y puedes perfil para mostrar que el tiempo es perdido, en lugar de hacer que sea más difícil de usar al principio con la posible complejidad innecesaria.

He encontrado que el C++ lite FAQ de información como este.En particular, su pregunta es contestada por:

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

Usted puede asignar matriz de almacenamiento estático (en el archivo del alcance, o agregar static calificador en el ámbito de la función), si usted necesita sólo un ejemplo.

int array[800][800];

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

De esta manera no va a ir a la pila, y usted no tiene que lidiar con la memoria dinámica.

Bien, partiendo de lo de Niall Ryan comenzó, si el rendimiento es un problema, usted puede tomar un paso más allá mediante la optimización de las matemáticas y encapsulado en una clase.

Así que vamos a empezar con un poco de matemáticas.Recordemos que 800 puede ser escrito en potencias de 2, como:

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

Así que podemos escribir nuestros abordar la función como:

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

Así que si reunimos todo en una clase de niza, se obtiene:

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];
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top