que - ¿Los miembros flexibles de la matriz son válidos en C++?
bombas de miembros flexibles (6)
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ó compilar algún código usando clang en C ++, esa sintaxis 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 declaración 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 declaración correcta []
o [0]
?
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 compilació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<int> 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();
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] = ...;
}
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.
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 arquitecturas compatibles, esto consumirá 8 bytes más allocated
.
Por supuesto, todo esto es C pero g ++ por ejemplo lo acepta sin problemas.
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<int> foo;
};
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<int*>(&this[1]); } };
Ejemplo de uso:
#include <stdlib.h>
struct blah {
alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); }
};
int main()
{
blah *b = (blah*)malloc(sizeof(blah)+10*sizeof(int));
if(!b) return 1;
b->foo()[1]=1;
}