lenguaje estructuras estructura entre ejercicios ejemplo diferencia dev arreglo anidadas c++ struct

entre - Inicializando estructuras en C++



estructuras en c++ pdf (5)

8.5.1 / 12 "Agregados" dice:

Se consideran todas las conversiones de tipo implícitas (cláusula 4) al inicializar el miembro agregado con un inicializador desde una lista de inicializadores.

Asi que

A a = {0};

se inicializará con un char* NULL char* (como AndreyT y Johannes ), y

A a = {42};

fallará en el momento de la compilación ya que no hay una conversión implícita que coincida con un constructor std::string .

Como una adición a esta pregunta , ¿qué está pasando aquí?

#include <string> using namespace std; struct A { string s; }; int main() { A a = {0}; }

Obviamente, no puede establecer std :: string en cero. ¿Puede alguien proporcionar una explicación (respaldada con referencias al Estándar C ++, por favor) sobre lo que se supone que realmente suceda aquí? Y luego explica por ejemplo):

int main() { A a = {42}; }

¿Alguno de estos está bien definido?

Una vez más, una pregunta embarazosa para mí: siempre doy mis constructores de estructuras, por lo que el problema nunca ha surgido antes.


Como han señalado las personas, esto "funciona" porque string tiene un constructor que puede tomar 0 como parámetro. Si decimos:

#include <map> using namespace std; struct A { map <int,int> m; }; int main() { A a = {0}; }

entonces obtenemos un error de compilación, ya que la clase de mapa no tiene dicho constructor.


En 21.3.1 / 9, la norma prohíbe que el argumento char* del constructor relevante de std::basic_string sea ​​un puntero nulo. Esto debería arrojar un std::logic_error , pero todavía tengo que ver en qué parte del estándar está la garantía de que violar una precondición arroja un std::logic_error .


Su estructura es un agregado , por lo que las reglas ordinarias para la inicialización agregada funcionan para él. El proceso se describe en 8.5.1. Básicamente todo el 8.5.1 está dedicado a él, así que no veo la razón para copiar todo aquí. La idea general es prácticamente la misma en C, solo se adaptó a C ++: se toma un inicializador de la derecha, se toma un miembro de la izquierda y se inicializa el miembro con ese inicializador. De acuerdo con 8.5 / 12, esto será una copia inicialización .

Cuando tu lo hagas

A a = { 0 };

básicamente está inicializando la copia as con 0 , es decir, as que es semánticamente equivalente a

string s = 0;

La anterior compila porque std::string es convertible desde un puntero const char * . (Y es un comportamiento indefinido, ya que el puntero nulo no es un argumento válido en este caso).

Su versión 42 no compilará por la misma razón que

string s = 42;

no compilará 42 no es una constante de puntero nulo, y std::string no tiene medios para la conversión de tipo int .

PD Por las dudas: tenga en cuenta que la definición de agregado en C ++ no es recursiva (a diferencia de la definición de POD, por ejemplo). std::string no es un agregado, pero no cambia nada para su A A sigue siendo un agregado.


0 es una constante de puntero nulo

S.4.9:

Una constante de puntero nulo es una expresión de constante integral (5.19) rvalor de tipo entero que se evalúa como cero.

Una constante de puntero nulo se puede convertir a cualquier otro tipo de puntero:

S.4.9:

Una constante de puntero nulo se puede convertir a un tipo de puntero; el resultado es el valor del puntero nulo de ese tipo

Lo que dio para la definición de A se considera un agregado:

S.8.5.1:

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

Está especificando una cláusula de inicialización:

S.8.5.1:

Cuando se inicializa un agregado, el inicializador puede contener una cláusula de inicialización que consiste en una lista de cláusulas de inicializador separadas por comas y separadas por comas para los miembros del agregado.

A contiene un miembro del agregado de tipo std::string y la cláusula de inicialización se aplica a él.

Su agregado está inicializado con copia

Cuando un agregado (ya sea clase o matriz) contiene miembros del tipo de clase y se inicializa mediante una lista de inicializadores incluida, cada uno de dichos miembros se inicializa con copia.

Copiar inicialización significa que tiene el equivalente a std::string s = 0 o std::string s = 42 ;

S.8.5-12

La inicialización que ocurre en el paso de argumento, el retorno de función, el lanzamiento de una excepción (15.1), el manejo de una excepción (15.3) y las listas de inicializadores incluidos (8.5.1) se llama inicialización de copia y es equivalente a la forma T x = un;

std::string s = 42 no compilará porque no hay una conversión implícita, std::string s = 0 compilará (porque existe una conversión implícita) pero da como resultado un comportamiento indefinido.

El constructor de std::string para const char* no está definido como explicit que significa que puede hacer esto: std::string s = 0

Solo para mostrar que las cosas se están inicializando con copia, puede hacer esta simple prueba:

class mystring { public: explicit mystring(const char* p){} }; struct A { mystring s; }; int main() { //Won''t compile because no implicit conversion exists from const char* //But simply take off explicit above and everything compiles fine. A a = {0}; return 0; }