¿Es posible inicializar estructuras en C ++ como se indica a continuación?
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
Los enlaces aquí y aquí mencionan que es posible usar este estilo solo en C. Si es así, ¿por qué esto no es posible en C ++? ¿Hay alguna razón técnica subyacente por la que no se implementa en C ++, o es una mala práctica usar este estilo? Me gusta usar esta forma de inicialización porque mi estructura es grande y este estilo me da una clara legibilidad de qué valor se asigna a cada miembro.
Comparta conmigo si hay otras formas a través de las cuales podemos lograr la misma legibilidad.
He referido los siguientes enlaces antes de publicar esta pregunta
Respuestas:
Si desea dejar en claro cuál es el valor de cada inicializador, simplemente divídalo en varias líneas, con un comentario en cada una:
fuente
char*
) como uno de los otros miembros arriba o abajo en la estructura, porque no hay riesgo de intercambiarlos.(struct timeval){ .seconds = 0, .microseconds = 100 }
siempre será cien microsegundos, perotimeval { 0, 100 }
podría ser cien SEGUNDOS . No querrás encontrar algo así por las malas.Después de que mi pregunta no resultó en un resultado satisfactorio (porque C ++ no implementa init basado en etiquetas para estructuras), tomé el truco que encontré aquí: ¿Los miembros de una estructura C ++ se inicializan a 0 de manera predeterminada?
Para ti equivaldría a hacer eso:
Este es sin duda el más cercano a lo que quería originalmente (cero todos los campos excepto los que desea inicializar).
fuente
static address temp_address = {};
trabajará. Llenarlo después depende del tiempo de ejecución, sí. Puede pasar por alto esto proporcionando una función estática que hace el init para usted:static address temp_address = init_my_temp_address();
.init_my_temp_address
puede ser una función lambda:static address temp_address = [] () { /* initialization code */ }();
address
y nunca sabrá de todos los lugares que creanaddress
y ahora no inicializa su nuevo miembro.Como otros han mencionado, este se denomina inicializador.
Esta característica es parte de C ++ 20
fuente
Los identificadores de campo son de hecho sintaxis de inicializador C. En C ++ solo da los valores en el orden correcto sin los nombres de campo. Desafortunadamente, esto significa que debe darlos a todos (en realidad, puede omitir los campos finales de valor cero y el resultado será el mismo):
fuente
Esta característica se llama inicializadores designados . Es una adición al estándar C99. Sin embargo, esta característica quedó fuera de C ++ 11. De acuerdo con el lenguaje de programación C ++, 4a edición, Sección 44.3.3.2 (Características C no adoptadas por C ++):
La gramática C99 tiene los inicializadores designados [Ver ISO / IEC 9899: 2011, Borrador del Comité N1570 - 12 de abril de 2011]
6.7.9 Inicialización
Por otro lado, el C ++ 11 no tiene los inicializadores designados [Ver ISO / IEC 14882: 2011, Borrador del Comité N3690 - 15 de mayo de 2013]
8.5 Inicializadores
Para lograr el mismo efecto, use constructores o listas de inicializadores:
fuente
Simplemente puede inicializar a través de ctor:
fuente
struct address
. Además, los tipos de POD a menudo intencionalmente no tienen constructor ni destructor.Incluso puede empaquetar la solución de Gui13 en una sola declaración de inicialización:
Descargo de responsabilidad: no recomiendo este estilo
fuente
address
y el código aún se compilará con un millón de lugares solo inicializando los cinco miembros originales. La mejor parte de la inicialización de la estructura es que puedes tener todos los miembrosconst
y te obligará a inicializarlos a todosSé que esta pregunta es bastante antigua, pero encontré otra forma de inicializar, usando constexpr y curry:
Este método también funciona para variables globales estáticas e incluso constexpr. La única desventaja es la mala capacidad de mantenimiento: cada vez que se debe inicializar otro miembro utilizando este método, se deben cambiar todos los métodos de inicialización del miembro.
fuente
Podría estar perdiendo algo aquí, por qué no:
fuente
No está implementado en C ++. (también,
char*
cadenas? Espero que no).Por lo general, si tiene tantos parámetros, es un olor a código bastante serio. Pero, en cambio, ¿por qué no simplemente inicializar el valor de la estructura y luego asignar a cada miembro?
fuente
char*
¿cuerdas? Espero que no)". - Bueno, es un ejemplo de C.char*
peroconst char*
es mucho más seguro y todo el mundo lo usastd::string
porque es mucho más confiable.Encontré esta forma de hacerlo para las variables globales, que no requiere modificar la definición de estructura original:
luego declare la variable de un nuevo tipo heredado del tipo de estructura original y use el constructor para la inicialización de campos:
Aunque no es tan elegante como el estilo C ...
Para una variable local, requiere un memset adicional (this, 0, sizeof (* this)) al comienzo del constructor, por lo que claramente no es peor y la respuesta de @ gui13 es más apropiada.
(Tenga en cuenta que 'temp_address' es una variable de tipo 'temp_address', sin embargo, este nuevo tipo hereda de 'address' y se puede usar en todos los lugares donde se espera 'address', por lo que está bien).
fuente
Hoy me enfrenté a un problema similar, donde tengo una estructura que quiero llenar con datos de prueba que se pasarán como argumentos a una función que estoy probando. Quería tener un vector de estas estructuras y estaba buscando un método de una línea para inicializar cada estructura.
Terminé yendo con una función de constructor en la estructura, que creo que también se sugirió en algunas respuestas a su pregunta.
Probablemente sea una mala práctica hacer que los argumentos para el constructor tengan los mismos nombres que las variables miembro públicas, lo que requiere el uso del
this
puntero. Alguien puede sugerir una edición si hay una mejor manera.Lo que usé en mi función de prueba para llamar a la función que se está probando con varios argumentos como este:
fuente
Es posible, pero solo si la estructura que está inicializando es una estructura POD (datos antiguos simples). No puede contener ningún método, constructor o incluso valores predeterminados.
fuente
En C ++, los inicializadores de estilo C fueron reemplazados por constructores que, en tiempo de compilación, pueden garantizar que solo se realicen inicializaciones válidas (es decir, después de la inicialización, los miembros del objeto son consistentes).
Es una buena práctica, pero a veces es útil una preinicialización, como en su ejemplo. OOP resuelve esto mediante clases abstractas o patrones de diseño de creación .
En mi opinión, usar esta forma segura mata la simplicidad y, a veces, la compensación de seguridad puede ser demasiado costosa, ya que el código simple no necesita un diseño sofisticado para mantenerse mantenible.
Como solución alternativa, sugiero definir macros usando lambdas para simplificar la inicialización para que se vea casi como el estilo C:
La macro DIRECCIÓN se expande a
que crea y llama a la lambda. Los parámetros de macro también están separados por comas, por lo que debe poner entre paréntesis el inicializador y llamar como
También podría escribir macro inicializador generalizado
pero entonces la llamada es un poco menos hermosa
sin embargo, puede definir la macro DIRECCIÓN usando la macro INIT general fácilmente
fuente
En GNUC ++ (parece estar obsoleto desde 2.5, hace mucho tiempo :) Vea las respuestas aquí: Inicialización de estructura mediante etiquetas. Funciona, pero ¿cómo? ), es posible inicializar una estructura como esta:
fuente
Inspirado por esta respuesta realmente ordenada: ( https://stackoverflow.com/a/49572324/4808079 )
Puedes hacer cierres de lamba:
.
O, si quieres ser muy elegante
Hay algunos inconvenientes relacionados con esto, principalmente relacionados con miembros no iniciados. Por lo que dicen los comentarios de las respuestas vinculadas, se compila de manera eficiente, aunque no lo he probado.
En general, creo que es un enfoque ordenado.
fuente