¿Los miembros flexibles de la matriz son válidos en C ++?

En C99, puede declarar un miembro de matriz flexible de una estructura como tal:

struct blah { int foo[]; }; 

Sin embargo, cuando alguien aquí en el trabajo intentó comstackr algún código usando clang en C ++, esa syntax no funcionó. (Había estado trabajando con MSVC.) Tuvimos que convertirlo a:

 struct blah { int foo[0]; }; 

Revisando el estándar de C ++, no encontré ninguna referencia a matrices de miembros flexibles; Siempre pensé que [0] era una statement inválida, pero aparentemente para una matriz de miembros flexible es válida. ¿Las matrices de miembros flexibles son realmente válidas en C ++? Si es así, ¿es la statement correcta [] o [0] ?

C ++ se estandarizó por primera vez en 1998, por lo que es anterior a la adición de miembros de matriz flexible a C (que era nuevo en C99). Hubo un corrigendum para C ++ en 2003, pero eso no agregó ninguna característica nueva relevante. La próxima revisión de C ++ (C ++ 0x) aún está en desarrollo, y parece que los miembros flexibles de la matriz no se agregan a ella.

C ++ no es compatible con los miembros de matriz flexible C99 al final de las estructuras, ya sea utilizando una notación de índice vacía o una notación de índice 0 (salvo las extensiones específicas del proveedor):

 struct blah { int count; int foo[]; // not valid C++ }; struct blah { int count; int foo[0]; // also not valid C++ }; 

Por lo que yo sé, C ++ 0x tampoco agregará esto.

Sin embargo, si dimensiona la matriz en 1 elemento:

 struct blah { int count; int foo[1]; }; 

las cosas son válidas y funcionan bastante bien. Puede asignar la memoria adecuada con una expresión que es poco probable que tenga errores uno a uno:

 struct blah* p = (struct blah*) malloc( offsetof(struct blah, foo[desired_number_of_elements]); if (p) { p->count = desired_number_of_elements; // initialize your p->foo[] array however appropriate - it has `count` // elements (indexable from 0 to count-1) } 

Por lo tanto, es portátil entre C90, C99 y C ++ y funciona tan bien como los miembros de matriz flexible de C99.

Raymond Chen hizo un buen comentario sobre esto: ¿por qué algunas estructuras terminan con una matriz de tamaño 1?

Nota: En el artículo de Raymond Chen, hay un error tipográfico / error en un ejemplo inicializando la matriz ‘flexible’. Debe leer:

 for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '=' TokenGroups->Groups[Index] = ...; } 

El segundo no contendrá elementos, sino que señalará justo después de blah . Entonces, si tienes una estructura como esta:

 struct something { int a, b; int c[0]; }; 

puedes hacer cosas como esta:

 struct something *val = (struct something *)malloc(sizeof(struct something) + 5 * sizeof(int)); val->a = 1; val->b = 2; val->c[0] = 3; 

En este caso, c se comportará como una matriz con 5 int s, pero los datos en la matriz serán posteriores a la estructura something .

El producto en el que estoy trabajando usa esto como una cadena de tamaño:

 struct String { unsigned int allocated; unsigned int size; char data[0]; }; 

Debido a las architectures compatibles, esto consumirá 8 bytes más allocated .

Por supuesto, todo esto es C pero g ++ por ejemplo lo acepta sin problemas.

Si solo quieres

 struct blah { int foo[]; }; 

entonces no necesitas la estructura en absoluto y simplemente puedes tratar con una matriz int malloc’ed / new’ed.

Si tienes algunos miembros al principio:

 struct blah { char a,b; /*int foo[]; //not valid in C++*/ }; 

luego en C ++, supongo que podrías reemplazar a foo con una función de miembro foo :

 struct blah { alignas(int) char a,b; int *foo(void) { return reinterpret_cast(&this[1]); } }; 

Ejemplo de uso:

 #include  struct blah { alignas(int) char a,b; int *foo(void) { return reinterpret_cast(&this[1]); } }; int main() { blah *b = (blah*)malloc(sizeof(blah)+10*sizeof(int)); if(!b) return 1; b->foo()[1]=1; } 

Both int foo[]; y int foo[0]; son incorrectos en C ++ (al menos en ese contexto). Use int *foo; .

Cuando declaras dicha matriz en C ++, su tamaño debe definirse en tiempo de comstackción. Es decir, debería especificar el tamaño de la matriz explícitamente, como int foo[5] o usar la lista de inicialización como int foo[] = {1, 2, 3} . Desafortunadamente, no puede usar la lista de inicialización para la inicialización del miembro de la clase.

EDITAR

Para fines de serialización, use std::vector foo . Una vez que se completa, puede obtener fácilmente un puntero a una matriz de enteros y su tamaño:

 int* begin = &foo[0]; std::size_t size = foo.size(); 

La mejor solución es declararlo como un puntero:

 struct blah { int* foo; }; 

O mejor aún, declararlo como un std::vector :

 struct blah { std::vector foo; };