2011-03-17 10 views
17

Antes que nada, quiero asegurarles que estoy haciendo esta pregunta por curiosidad. Quiero decir, no me digas que si necesito esto, entonces mi diseño tiene problemas porque no necesito esto en código real. Espero que convencí a ti :) Ahora a la pregunta: ¿¿Es posible crear dinámicamente una matriz de tamaño constante en C++?

Para la mayoría de los tipos T podemos escribir

T* p = new T; 

ahora lo que si T es un tipo de matriz?

int (*p)[3] = new ???; //pointer to array of 3 = new ??? 

yo probamos este:

typedef int arr[3]; 
arr* p = new arr; 

pero esto no funciona.

¿Hay alguna sintaxis válida para esto o es imposible en C++. Si es imposible, ¿por qué? Gracias

Edición: Estoy adivinando que no era lo suficientemente claro. Quiero ser capaz de utilizarlo en esta situación:

void f(int(&)[3]); 
int (*p)[3] = new ???; 
f(*p); 
+0

Si he entendido bien, que desea para saber si C++ tiene una forma de "inferir" el tamaño de la matriz sin especificarlo explícitamente en la asignación? –

+0

@oakley: no del todo: me pregunto si uso una sintaxis 'T * p = mew T;' cuando T es un tipo de matriz (con dimensión conocida en tiempo de compilación) –

Respuesta

10

La razón por la que no puede hacerlo es que new int[3] ya asigna exactamente lo que desea, un objeto de tipo int[3]. Es solo que la nueva expresión devuelve, es un puntero a su primer elemento. 5.3.4/1:

Si la entidad es un objeto no array, la nueva expresión devuelve un puntero al objeto creado. Si es una matriz , la nueva expresión devuelve un puntero al elemento inicial de la matriz .

devolviendo un puntero al primer elemento es lo que permite la 3 para ser desconocida hasta el tiempo de ejecución, por lo que supongo que al saberlo de antemano, que ha tropezaste con la flexibilidad que no se está utilizando.

Supongo que las formas de evitar esto son reinterpretar_cast de nuevo al tipo de puntero que desee (no necesariamente portátil), o asignar una estructura que contenga un int[3] (y use un puntero a su miembro de datos).

[Editar: er, sí, o la idea de FredOverflow, que no tiene ni desventaja, pero requiere el uso de delete[] en lugar de delete.]

supongo que la moral es, si se escribe plantillas que ingenuamente asignar algún tipo desconocido T con new, entonces la plantilla no funcionará cuando alguien pase un tipo de matriz como T. Lo asignará al tipo de puntero incorrecto y, si lo soluciona (quizás con auto), lo eliminará incorrectamente.

Editar en respuesta a la pregunta de j_kubik:

Ésta es una forma de distinguir entre la matriz y no la matriz tipos. Si se escribe una función como esta, que devuelve un objeto que contiene el puntero y es capaz de eliminarlo correctamente, entonces usted tiene un nuevo genérico/borrar para cualquier tipo T.

#include <iostream> 

template <typename T> 
void make_thing_helper(T *) { 
    std::cout << "plain version\n"; 
} 

template <typename T, int N> 
void make_thing_helper(T (*)[N]) { 
    std::cout << "array version\n"; 
} 

template <typename T> 
void make_thing() { 
    make_thing_helper((T*)0); 
} 

int main() { 
    typedef int T1; 
    typedef int T2[3]; 
    make_thing<T1>(); 
    make_thing<T2>(); 
} 
+1

Ambos 'new int [3]' y 'new int [1] [3]' tienen que ser liberados a través de 'delete []'. – fredoverflow

+1

@FredOverflow: de hecho, quise decir "en lugar de" lo que sucede con un tipo que no es de matriz. Si estaba inventando la sintaxis mágica inexistente que quiere Armen, asignar un solo objeto de tipo matriz * como si * fuera un tipo que no fuera de matriz, entonces le permitiría eliminarlo con 'eliminar' a través del mismo puntero que se devuelve de 'MagicNew'. Así que se vería como' typedef int arr [3]; arr * p = MagicNew arr; borrar p; '. Sé que no especificó esto en su pregunta, quizás fue un error asumir que los demás lo inventarían de la misma manera. –

+0

Entonces, para resumir, ¿hay alguna manera de hacer new-delete template ready for array types or is impossible? –

-2

Usted acaba de hacer

int *p = new unsigned int [3] 

continuación, puede utilizar *p como un puntero o un array es decir *(p+1) or p[1]

+2

Lo siento, pero esto no es lo que soy preguntando. En absoluto –

11

Para obtener un puntero a una matriz de new, debe asignar dinámicamente una matriz bidimensional:

int (*p)[3] = new int[1][3]; 
+0

Hmm ... no es exactamente lo que esperaba pero ciertamente mi ejemplo funcionará ... +1 –

2

Siempre puedes usar boost :: array, que estará en C++ 0x. De lo contrario, cualquier solución será incómoda en el mejor de los casos: las matrices están rotas en C, y C++ mantiene la compatibilidad con C en este sentido . Fred Overflow ofreció una solución; incluso más fácil (pero sintácticamente ruidoso) sería envolver la matriz en una struct: struct A {int arr [3]; }; y asignar y manipular esto.

+0

Eso sería una solución, no una solución :) Y @ Fred también lo es, pero al menos mi ejemplo funciona con su solución alternativa Con los tuyos, no lo haría, ¿verdad? –

+1

El contenedor es una solución alternativa, pero boost: array sería mi solución preferida para trabajar con arreglos de tamaño fijo. Muy raro pero posible: void f (array <3> & p); array <3> * p = nueva matriz <3>; f (* p); – stefaanv

Cuestiones relacionadas