Por defecto, el valor y el cero de inicialización lío

Estoy muy confundido sobre el valor & default- & inicialización de cero.
y especialmente cuando se patada en para los diferentes estándares C++03 y C++11 (y C++14).

Estoy citando y tratando de extender una muy buena respuesta Valor/Default-/Cero – Init C++98 y C++03 aquí para hacerlo más general, ya que ayudaría a muchos de los usuarios, si alguien pudiera ayudar a llenar los necesarios huecos para tener una buena visión general sobre lo que ocurre cuando?

La visión de conjunto, por ejemplos, en pocas palabras:

A veces la memoria devuelta por el nuevo operador será inicializado, y a veces no, dependiendo de si el tipo que te newing es un POD (plain old datos), o si es una clase que contiene POD miembros y es el uso de un compilador genera constructor predeterminado.

  • En C++1998 hay 2 tipos de inicialización: cero y defecto-inicialización
  • En C++2003 un 3er tipo de inicialización, el valor de inicialización fue añadido.
  • En C++2011/C++2014 sólo lista de inicialización de fue añadido y el reglamento por de valor/default-/inicialización de cero cambiado un poco.

Asumir:

struct A { int m; };                     
struct B { ~B(); int m; };               
struct C { C() : m(){}; ~C(); int m; };  
struct D { D(){}; int m; };             
struct E { E() = default; int m;} /** only possible in c++11/14 */  
struct F {F(); int m;}  F::F() = default; /** only possible in c++11/14 */

En un compilador de C++98, el siguiente debe producirse:

  • new A – valor indeterminado (A es POD)
  • new A()– cero inicializar
  • new B – defecto de construcción (B::m no está inicializada, B es no-POD)
  • new B() – defecto de construcción (B::m está sin inicializar)
  • new C – defecto de construcción (C::m es inicializada en cero, C es no-POD)
  • new C() – defecto de construcción (C::m es inicializada en cero)
  • new D – defecto de construcción (D::m no está inicializada, D es no-POD)
  • new D()defecto construir? (D::m está sin inicializar)

En C++03 adecúa compilador, las cosas deberían funcionar así:

  • new A – valor indeterminado (A es POD)
  • new A() – valor-inicializar A, que es la inicialización de cero, ya que es un POD.
  • new B – default-inicializa (hojas B::m sin inicializar, B es no-POD)
  • new B() – valor-inicializa B que cero inicializa todos los campos, desde su defecto cto r es el compilador genera como contraposición a la definida por el usuario.
  • new C – default-inicializa C, que llama a la predeterminada cto r. (C::m es inicializada en cero, C es no-POD)
  • new C() – valor-inicializa C, que llama a la predeterminada cto r. (C::m es inicializada en cero)
  • new D – defecto de construcción (D::m no está inicializada, D es no-POD)
  • new D()de valor se inicializa D?, que llama a la predeterminada cto r (D::m está sin inicializar)

Cursiva los valores de y ? de dudas, por favor ayuda para corregir este problema 🙂

En C++11 adecúa compilador, las cosas deberían funcionar así:

??? (por favor, ayuda si empiezo aquí, que de todos modos van mal)

En C++14 adecúa compilador, las cosas deberían funcionar así:
??? (por favor, ayuda si empiezo aquí, que de todos modos van mal)
(Proyecto basado en la respuesta)

  • new A – default-inicializa A, compilador gen. cto r, (dejando A::m sin inicializar) (A es POD)
  • new A() – valor-inicializa A, que es la inicialización de cero desde el 2 de. punto en [dcl.init]/8

  • new B – default-inicializa B, compilador gen. cto r, (dejando B::m sin inicializar) (B es no-POD)

  • new B() – valor-inicializa B que cero inicializa todos los campos, desde su defecto cto r es el compilador genera como contraposición a la definida por el usuario.
  • new C – default-inicializa C, que llama a la predeterminada cto r. (C::m es inicializada en cero, C es no-POD)
  • new C() – valor-inicializa C, que llama a la predeterminada cto r. (C::m es inicializada en cero)
  • new D – default-inicializa D (D::m no está inicializada, D es no-POD)
  • new D() – valor-inicializa D, que llama a la predeterminada cto r (D::m está sin inicializar)
  • new E – default-inicializa E, que llama a la comp. gen. cto r. (E::m no está inicializada, E es no-POD)
  • new E() – valor-inicializa E, que cero inicializa E desde el 2 de punto en [dcl.init]/8 )
  • new F – default-inicializa F, que llama a la comp. gen. cto r. (F::m no está inicializada, F es no-POD)
  • new F() – valor-inicializa F, que defecto-inicializa F desde el 1 de. punto en [dcl.init]/8 (F cto r de la función es proporcionada por el usuario si es que el usuario declara y no de forma explícita en mora o que se eliminen en su primera declaración. Enlace)
  • hay una buena explicación de esto aquí: en.cppreference.com/w/cpp/language/default_constructor
  • Como lo que yo puedo decir, sólo hay una diferencia entre C++98 y C++03 en estos ejemplos. El problema parece ser que se describe en N1161 (hay revisiones posteriores de dicho documento) y CWG DR #178. La redacción que se necesitan para cambiar en C++11, debido a las nuevas características y una nueva especificación de la VAINA, y se cambió de nuevo en C++14 debido a defectos en el C++11 de redacción, pero los efectos en estos casos no se cambian.
  • Mientras aburrido, struct D { D() {}; int m; }; puede ser vale la pena incluir en tu lista.
InformationsquelleAutor Gabriel | 2015-04-21

2 Kommentare

  1. 24

    C++14 especifica la inicialización de los objetos creados con new en [expr.nuevo]/17 ([expr.nuevo]/15 en C++11, y la nota no era una nota pero el texto normativo en aquel entonces):

    Un nueva expresión que se crea un objeto de tipo T inicializa que
    objeto de la siguiente manera:

    • Si el nuevo-inicializador se omite, el objeto es defecto-inicializa (8.5). [ Nota: Si no la inicialización es
      a cabo, el objeto tiene un valor indeterminado. — nota final de la ]
    • De lo contrario, el nuevo-inicializador se interpretan de acuerdo a la inicialización de las reglas de 8.5 para directa-inicialización.

    Defecto-inicialización se define en [dcl.init]/7 (/6 en C++11, y el propio texto tiene el mismo efecto):

    A defecto-inicializar un objeto de tipo T significa:

    • si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9), el constructor por defecto (12.1) para T se llama (y la inicialización
      está mal formado si T no tiene ningún constructor predeterminado o la resolución de sobrecarga
      (13.3) resultados en la ambigüedad o en una función que se elimina o se
      inaccesible desde el contexto de la inicialización);
    • si T es un tipo de matriz, cada elemento es defecto-inicializa;
    • de lo contrario, no la inicialización se realiza.

    Así

    • new A únicamente causas As constructor predeterminado a ser llamado, que no se inicializa m. Indeterminado valor. Debe ser el mismo para new B.
    • new A() se interpretan de acuerdo a [dcl.init]/11 (/10 en C++11):

      Un objeto cuya inicializador es un conjunto de paréntesis vacío, es decir, (), será de valor inicializado.

      Y ahora considere [dcl.init]/8 (/7 en C++11†):

      A valor de inicialización un objeto de tipo T significa:

      • si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9), ya sea con ningún constructor predeterminado (12.1) o un constructor predeterminado que es
        proporcionado por el usuario o eliminado, entonces el objeto es el valor por defecto-inicializa;
      • si T es un (posiblemente cv-calificado) tipo de clase, sin proporcionado por el usuario o eliminados constructor por defecto, entonces el objeto es
        inicializados a cero y la semántica de las restricciones para
        defecto-inicialización se revisan, y si T tiene un no-trivial defecto
        constructor, el objeto es el valor por defecto-inicializa;
      • si T es un tipo de matriz, cada elemento es el valor inicializado;
      • de lo contrario, el objeto es inicializada en cero.

      Por lo tanto new A() volverá a cero inicializar m. Y esto debe ser equivalente para A y B.

    • new C y new C() se predeterminado-inicializar de nuevo el objeto, desde la primera viñeta de la última cita que se aplica (C ha proporcionado por el usuario constructor por defecto!). Pero, claramente, ahora m se inicializa en el constructor en ambos casos.


    † Bien, este párrafo tiene ligeramente diferentes redacción en C++11, que no altera el resultado:

    A valor de inicialización un objeto de tipo T significa:

    • si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9) con un
      proporcionados por el usuario constructor (12.1), entonces el constructor predeterminado para T
      se llama (y la inicialización está mal formado, si T no es accesible
      constructor predeterminado);
    • si T es un (posiblemente cv-calificado) no unión
      tipo de clase, sin proporcionado por el usuario constructor, entonces el objeto es
      inicializados a cero y, si T‘s implícitamente-declaró constructor predeterminado
      no es trivial, que el constructor es llamado.
    • si T es un tipo de matriz,
      a continuación, cada elemento es el valor inicializado;
    • de lo contrario, el objeto es
      inicializados a cero.
    • de verdad que no.
    • ah por lo que usted está hablando principalmente acerca de c++14 y referencias para c++11 se dan entre paréntesis
    • Correcto. Me refiero a, C++14 es el último estándar, de modo que es a la palestra.
    • El molesto cosa acerca de tratar de seguimiento de inicialización de reglas a través de las normas es que muchos de los cambios (la mayoría? todos?) entre los publicados en C++14 y C++11 normas que pasó a través de DRs, y lo son de facto de C++11. Y luego también hay post-C++14 DRs…
    • DR = Defecto de Informes
    • Todavía no entiendo por qué struct A { int m; }; struct C { C() : m(){}; int m; };producir resultados diferentes y lo hace m de Un a ser inicializado en el primer lugar. He abierto un hilo dedicado para el experimento que hice y os agradezco de entrada hay que aclarar la cuestión. Gracias stackoverflow.com/questions/45290121/…

  2. 12

    La siguiente respuesta se extiende la respuesta https://stackoverflow.com/a/620402/977038 que sirva de referencia para C++ 98 y C++ 03

    Citando la respuesta

    1. En C++1998 hay 2 tipos de inicialización: el cero y el valor predeterminado
    2. En C++2003 un 3er tipo de inicialización, el valor de inicialización se
      añadido.

    C++11 (En referencia a n3242)

    Inicializadores de

    8.5 Inicializadores [dcl.init] especifica que una variable POD o no POD puede inicializarse como llave o igual inicializador que puede ser armado-init-lista de o inicializador-cláusula aggregately conoce como llave o igual inicializador o el uso de ( expresión-lista ). Anterior a la de C++11, sólo (expresión-lista) o inicializador-cláusula fue apoyado aunque inicializador-cláusula es más restringida de lo que tienen en C++11. En C++11, inicializador-cláusula ahora soporta armado-init-lista de aparte de asignación de expresión como fue en C++03. La siguiente gramática resume la nueva admite la cláusula, donde la parte que está en negrita es recién agregado en el estándar C++11.

    inicializador:

        abrazadera o igual inicializador

        ( expresión-lista )

    abrazadera o igual inicializador:

        = initializer-cláusula

        reforzadas-init-lista

    inicializador-cláusula:

        la asignación de expresión

        reforzadas-init-lista

    inicializador de la lista:

        inicializador-cláusula …optar

        inicializador-lista de inicializador-cláusula …opt**

    reforzadas-init-lista:

        { inicializador-lista opt }

        { }

    De inicialización

    Igual que en C++03, C++11 todavía admite tres forma de inicializar


    Nota

    La parte resaltada en negrita ha sido añadido en C++11 y el que se striked ha sido retirado de C++11.

    1. Inicializador de Tipo:8.5.5 [dcl.init] _zero-initialize_

    A cabo en los siguientes casos

    • Objetos estáticos o de hilo tiempo de almacenamiento son inicializados a cero
    • Si hay menos inicializadores de que hay elementos de la matriz, cada elemento explícitamente no se inicializa serán inicializados a cero
    • Durante valor de inicialización, si T es un (posiblemente cv-calificado) no unión de tipo de clase, sin proporcionado por el usuario constructor, entonces el objeto es inicializada en cero.

    A cero inicializar un objeto o referencia de tipo T significa:

    • si T es un tipo escalar (3.9), el objeto se establece en el valor 0 (cero), tomado como una integral de la expresión de la constante de, convierten a T;
    • si T es un (posiblemente cv-calificado) la no unión de tipo de clase, cada uno de los miembro de datos estáticos y cada uno de la clase de base subobjeto es inicializada en cero y el relleno es inicializado a cero bits;
    • si T es un (posiblemente cv-calificado) tipo de unión, el objeto del primer no-estático nombrado miembro de datos es cero inicializa y el relleno es inicializado a cero bits;
    • si T es un tipo de matriz, cada elemento es inicializada en cero;
    • si T es un tipo de referencia, ya que la inicialización se realiza.

    2. El inicializador de Tipo: 8.5.6 [dcl.init] _default-initialize_

    A cabo en los siguientes casos

    • Si la nueva inicializador es omitido, el objeto es el valor por defecto-inicializa; si no la inicialización se realiza, el objeto tiene un valor indeterminado.
    • Si no inicializador se especifica para un objeto, el objeto es el valor por defecto-inicializado, a excepción de los Objetos con estática o hilo de almacenamiento de duración
    • Cuando una clase base o un no-miembro de datos estáticos no es mencionado en una lista de inicializador de constructor y que el constructor es llamado.

    Predeterminadas inicializar un objeto de tipo T significa:

    • si T es un (posiblemente cv-calificado) no POD tipo de clase (Cláusula 9), el constructor predeterminado para T se llama (y la inicialización está mal formado, si T no es accesible constructor predeterminado);
    • si T es un tipo de matriz, cada elemento es el valor por defecto-inicializa;
    • de lo contrario, no la inicialización se realiza.

    Nota Hasta C++11, sólo que no POD tipos de clase con almacenamiento automático duración se considera defecto-inicializa cuando no inicializador se utiliza.


    3. El inicializador de Tipo: 8.5.7 [dcl.init] _value-initialize_

    1. Cuando un objeto(nombre temporal, denominada variable, dinámico el tiempo de almacenamiento o no miembro de datos estáticos), cuya inicializador es un conjunto de paréntesis vacío, es decir, () o llaves {}

    Valores para inicializar un objeto de tipo T significa:

    • si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9) con un proporcionados por el usuario constructor (12.1), entonces el constructor predeterminado para T se llama (y la inicialización está mal formado, si T no es accesible
      constructor predeterminado);
    • si T es un (posiblemente cv-calificado) no unión de tipo de clase, sin proporcionado por el usuario constructor, a continuación, cada miembro de datos estáticos y de la clase de base de los componentes de T es el valor inicializado; el objeto es inicializada en cero y, si T implícitamente-declaró constructor predeterminado es no trivial, que el constructor es llamado.
    • si T es un tipo de matriz, cada elemento es el valor inicializado;
    • de lo contrario, el objeto es inicializada en cero.

    Entonces, para resumir

    Nota La correspondiente cita de la norma se destaca en negrita

    • nuevo Un : default-inicializa (deja Un::m sin inicializar)
    • new a() : Cero inicializar Una, ya que el valor inicializado candidato no han proporcionado por el usuario o eliminados constructor predeterminado. si T es un (posiblemente cv-calificado) no unión de tipo de clase, sin proporcionado por el usuario constructor, entonces el objeto es inicializada en cero y, si T implícitamente-declaró constructor predeterminado es no trivial, que el constructor es llamado.
    • nueva B : default-inicializa (hojas B::m sin inicializar)
    • new B() : valor-inicializa B que cero inicializa todos los campos; si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9) con un proporcionados por el usuario constructor (12.1), entonces el constructor predeterminado para T se llama
    • nueva C : por defecto-inicializa C, que llama a la predeterminada cto r. si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9), el constructor predeterminado para T se llama, por otra parte, Si la nueva inicializador es omitido, el objeto es el valor por defecto-inicializa
    • new C() : valor-inicializa C, que llama a la predeterminada cto r. si T es un (posiblemente cv-calificado) tipo de clase (Cláusula 9) con un proporcionados por el usuario constructor (12.1), entonces el constructor predeterminado para T se llama. Por otra parte, Un objeto cuya inicializador es un conjunto de paréntesis vacío, es decir, (), será el valor inicializado

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea