una resueltos programación programacion orientada objetos miembros metodos ejercicios ejemplos codigo clases clase c++ c

c++ - resueltos - ¿Qué significa{0} al inicializar un objeto?



programacion orientada a objetos c++ ejemplos (9)

Cuando se usa {0} para inicializar un objeto, ¿qué significa? No puedo encontrar ninguna referencia a {0} ninguna parte, y debido a las llaves de búsqueda de Google no son útiles.

Código de ejemplo:

SHELLEXECUTEINFO sexi = {0}; // what does this do? sexi.cbSize = sizeof(SHELLEXECUTEINFO); sexi.hwnd = NULL; sexi.fMask = SEE_MASK_NOCLOSEPROCESS; sexi.lpFile = lpFile.c_str(); sexi.lpParameters = args; sexi.nShow = nShow; if(ShellExecuteEx(&sexi)) { DWORD wait = WaitForSingleObject(sexi.hProcess, INFINITE); if(wait == WAIT_OBJECT_0) GetExitCodeProcess(sexi.hProcess, &returnCode); }

Sin él, el código anterior se bloqueará en el tiempo de ejecución.


En respuesta a la razón por la que ShellExecuteEx() se bloquea: su SHELLEXECUTEINFO "sexi" SHELLEXECUTEINFO tiene muchos miembros y solo está inicializando algunos de ellos.

Por ejemplo, el miembro sexi.lpDirectory podría estar apuntando a cualquier lugar, pero ShellExecuteEx() aún intentará usarlo, por lo que obtendrá una violación de acceso a la memoria.

Cuando incluyes la línea:

SHELLEXECUTEINFO sexi = {0};

antes del resto de la configuración de su estructura, le está diciendo al compilador que ponga a cero a todos los miembros de la estructura antes de inicializar los específicos en los que está interesado. ShellExecuteEx() sabe que si sexi.lpDirectory es cero, debe ignorarlo.


Ha pasado un tiempo desde que trabajé en c / c ++ pero IIRC, el mismo método abreviado también se puede usar para arreglos.


Lo que está pasando aquí se llama inicialización agregada . Aquí está la definición (abreviada) de un agregado de la sección 8.5.1 de la especificación ISO:

Un agregado es una matriz o una clase sin constructores declarados por el usuario, sin miembros de datos no estáticos privados o protegidos, sin clases de base y sin funciones virtuales.

Ahora, usar {0} para inicializar un agregado como este es básicamente un truco para poner en 0 todo el asunto. Esto se debe a que al usar la inicialización agregada no tiene que especificar todos los miembros y la especificación requiere que todos los miembros no especificados estén inicializados de manera predeterminada, lo que significa que se establece en 0 para los tipos simples.

Aquí está la cita relevante de la especificación:

Si hay menos inicializadores en la lista que miembros en el agregado, entonces cada miembro que no se inicialice explícitamente se inicializará por defecto. Ejemplo:

struct S { int a; char* b; int c; }; S ss = { 1, "asdf" };

inicializa ss.a con 1 , ss.b con "asdf" y ss.c con el valor de una expresión de la forma int() , es decir, 0 .

Puede encontrar la especificación completa sobre este tema here


Siempre me he preguntado por qué debería usar algo como

struct foo bar = { 0 };

Aquí hay un caso de prueba para explicar:

cheque.c

struct f { int x; char a; } my_zero_struct; int main(void) { return my_zero_struct.x; }

gcc -O2 -o check check.c con gcc -O2 -o check check.c y luego gcc -O2 -o check check.c la tabla de símbolos con readelf -s check | sort -k 2 readelf -s check | sort -k 2 (esto es con gcc 4.6.3 en ubuntu 12.04.2 en un sistema x64). Extracto:

59: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 48: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata 25: 0000000000601018 0 SECTION LOCAL DEFAULT 25 33: 0000000000601018 1 OBJECT LOCAL DEFAULT 25 completed.6531 34: 0000000000601020 8 OBJECT LOCAL DEFAULT 25 dtor_idx.6533 62: 0000000000601028 8 OBJECT GLOBAL DEFAULT 25 my_zero_struct 57: 0000000000601030 0 NOTYPE GLOBAL DEFAULT ABS _end

La parte importante aquí es que my_zero_struct está después de __bss_start . La sección ".bss" en un programa en C es la sección de memoria que se establece en cero antes de que se llame main (ver wikipedia) en .bss .

Si cambias el código de arriba a:

} my_zero_struct = { 0 };

Luego, el ejecutable "check" resultante se ve exactamente igual al menos con el compilador gcc 4.6.3 en ubuntu 12.04.2; my_zero_struct aún se encuentra en la sección .bss y, por lo tanto, se inicializará automáticamente a cero, antes de que se llame main .

Las sugerencias en los comentarios de que un memset podría inicializar la estructura "completa" tampoco es una mejora, porque la sección .bss se borra completamente, lo que también significa que la estructura "completa" se establece en cero.

Puede ser que el estándar del lenguaje C no mencione nada de esto, pero en un compilador de C del mundo real nunca he visto un comportamiento diferente.


También lo uso para inicializar cadenas por ejemplo.

char mytext[100] = {0};


Tenga en cuenta que un inicializador de agregado vacío también funciona:

SHELLEXECUTEINFO sexi = {}; char mytext[100] = {};


Una cosa a tener en cuenta es que esta técnica no establecerá los bytes de relleno en cero. Por ejemplo:

struct foo { char c; int i; }; foo a = {0};

No es lo mismo que:

foo a; memset(&a,0,sizeof(a));

En el primer caso, los bytes de relleno entre c y i no están inicializados. ¿Por qué te importaría? Bueno, si guarda estos datos en el disco o los envía a través de una red o lo que sea, podría tener un problema de seguridad.


{0} es una matriz anónima que contiene su elemento como 0.

Esto se utiliza para inicializar uno o todos los elementos de la matriz con 0.

por ejemplo, int arr [8] = {0};

En este caso, todos los elementos de arr se inicializarán como 0.


{0} es un inicializador válido para cualquier tipo (objeto completo), tanto en C como en C ++. Es un lenguaje común que se usa para inicializar un objeto a cero ( sigue leyendo para ver qué significa eso).

Para los tipos escalares (tipos aritméticos y de puntero), las llaves son innecesarias, pero se permiten explícitamente. Citando el borrador N1570 de la norma ISO C, sección 6.7.9:

El inicializador para un escalar será una expresión única, opcionalmente encerrada entre llaves.

Inicializa el objeto a cero ( 0 para los enteros, 0.0 para el punto flotante, un puntero nulo para los punteros).

Para los tipos no escalares (estructuras, arreglos, uniones), {0} especifica que el primer elemento del objeto se inicializa a cero. Para estructuras que contienen estructuras, arreglos de estructuras, etc., esto se aplica recursivamente, por lo que el primer elemento escalar se establece en el cero, según sea apropiado para el tipo. Como en cualquier inicializador, cualquier elemento no especificado se pone a cero.

Las llaves intermedias ( { , } ) pueden omitirse; por ejemplo ambos son válidos y equivalentes:

int arr[2][2] = { { 1, 2 }, {3, 4} }; int arr[2][2] = { 1, 2, 3, 4 };

por lo que no tiene que escribir, por ejemplo, { { 0 } } para un tipo cuyo primer elemento no es escalar.

Así que esto:

some_type obj = { 0 };

es una forma abreviada de inicializar obj a cero, lo que significa que cada subobjeto escalar de obj se establece en 0 si es un número entero, 0.0 si es un punto flotante o un puntero nulo si es un puntero.

Las reglas son similares para C ++.

En su caso particular, ya que está asignando valores a sexi.cbSize y demás, está claro que SHELLEXECUTEINFO es una estructura o tipo de clase (o posiblemente una unión, pero probablemente no), por lo que no se aplica todo esto, sino que dicho { 0 } es un idioma común que se puede utilizar en situaciones más generales.

Esto no es (necesariamente) equivalente a usar memset para establecer la representación del objeto en todos los bits cero. Ni el punto flotante 0.0 ni el puntero nulo se representan necesariamente como todos los bits cero, y un inicializador { 0 } no establece necesariamente los bytes de relleno en ningún valor en particular. En la mayoría de los sistemas, sin embargo, es probable que tenga el mismo efecto.