tutorial español c++ c++11 constructor const language-lawyer

c++ - español - ¿Realmente necesito implementar el constructor proporcionado por el usuario para objetos const?



solidity español (3)

Tengo el codigo

class A { public: A() = default; private: int i = 1; }; int main() { const A a; return 0; }

Se compila bien en g ++ (ver ideone ), pero falla en clang ++ con error:

la inicialización predeterminada de un objeto de tipo const ''const A'' requiere un constructor predeterminado proporcionado por el usuario

Notifiqué este problema en el rastreador de errores de LLVM y lo obtuve INVÁLIDO.

Lo veo absolutamente inútil tratar de convencer a los desarrolladores de clang. Por otro lado, no veo la razón de tal restricción.

¿Puede alguien avisar si el Estándar C ++ 11 implica de alguna manera que este código no es válido? ¿O debería simplemente reportar un error a g ++? ¿O tal vez hay suficiente libertad en las reglas de lenguaje para manejar este código de muchas maneras?


N3797 §8.5 / 7 dice:

Si un programa solicita la inicialización predeterminada de un objeto de un tipo T constante-calificado, T será un tipo de clase con un constructor predeterminado provisto por el usuario.

No hay más ejemplo o explicación de esto. Estoy de acuerdo en que parece bastante extraño. Además, la regla se actualizó en C ++ 11 para ser más restrictiva que en C ++ 03, cuando los tipos de clase necesitaban constructores declarados por el usuario . (Su constructor es declarado por el usuario).

La solución es solicitar la inicialización de valor utilizando {} , o usar la inteligente definición en inline fuera de clase de Dietmar.

GCC proporciona un diagnóstico (y es bastante bueno, refiriéndose a los nuevos requisitos de C ++ 11) si agrega otro miembro sin un inicializador.

private: int i = 1; int j;

unmem.cpp:11:11: error: uninitialized const ‘a’ [-fpermissive] const A a; ^ unmem.cpp:1:7: note: ‘const class A’ has no user-provided default constructor class A { ^ unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body A() = default; ^ unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize ‘int A::j’ int j;

La source GCC se refiere al open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253 , ¿Por qué deben inicializarse los objetos const vacíos o completamente inicializados? Este es un problema abierto en el estándar, actualizado por última vez en agosto de 2011 (posterior a C ++ 11) con esta nota:

Si el constructor predeterminado implícito inicializa todos los subobjetos, no se requiere un inicializador.

Por lo tanto, mientras que Clang cumple con C ++ 11 (y cumplirá como está con C ++ 14), GCC está implementando las últimas ideas del comité de estandarización.

Archivado un error GCC . Predigo que necesitará -pedantic para obtener un diagnóstico cuando (y si) el error se corrige.


Tenga en cuenta que puede convertir su clase fácilmente en una que tenga un constructor predeterminado definido por el usuario:

class A { public: A(); private: int i = 1; }; inline A::A() = default;

De acuerdo con 8.4.2 [dcl.fct.def.default] párrafo 4:

... Una función miembro especial es proporcionada por el usuario si es declarada por el usuario y no está predeterminada o eliminada de forma explícita en su primera declaración. ...

Esto implica implícitamente que una función que no está explícitamente predeterminada en su primera declaración no es proporcionada por el usuario. En combinación con 8.5 [dcl.init] párrafo 6

... Si un programa solicita la inicialización predeterminada de un objeto de un tipo T calificado por el personal, T será un tipo de clase con un constructor predeterminado proporcionado por el usuario.

parece claro que no puede usar un constructor predeterminado predeterminado en su primera declaración para inicializar un objeto const . Sin embargo, puede usar una definición predeterminada si no es la primera declaración como se hace en el código anterior.


Edición: Lo siguiente se basa en información desactualizada. Acabo de pasar por N3797 y esto es lo que encontré:

§ 8.5 / 7 [dcl.init]
Si un programa solicita la inicialización predeterminada de un objeto de un tipo T constante-calificado, T será un tipo de clase con un constructor predeterminado provisto por el usuario.

Tenga en cuenta que la cita estándar en el enlace de abajo dice que el usuario lo declaró .

El siguiente programa compila en g ++ pero no clang ++:

struct A {}; void f() { A const a; }

Y podría estar relacionado con este informe de error donde se "reparó". g ++ no puede compilarlo una vez que contiene miembros de datos a menos que estén inicializados. Tenga en cuenta que int member = 1 ya no hará que A a POD. Comparativamente, clang ++ rechaza todas las permutaciones (clases vacías y miembros de datos inicializados o no). Para una interpretación de lo que significa el estándar por el siguiente párrafo:

§ 8.5 / 9 [dcl.init] dice:

Si no se especifica un inicializador para un objeto, y el objeto es de un tipo de clase no POD (posiblemente cv calificado) (o su matriz), el objeto se inicializará por defecto; si el objeto es de un tipo cualificado por constantes, el tipo de clase subyacente tendrá un constructor predeterminado declarado por el usuario. De lo contrario, si no se especifica un inicializador para un objeto, el objeto y sus subobjetos, si los hay, tienen un valor inicial indeterminado; Si el objeto o cualquiera de sus subobjetos son de tipo cualificado por const, el programa está mal formado.

Consulte ¿Por qué C ++ requiere que un constructor predeterminado provisto por el usuario construya por defecto un objeto const? . Supuestamente, el programa tiene if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized). Observe cómo se comporta g ++ para lo siguiente:

struct A {int a;}; struct B {int a = 1;}; int main() { A a; B b; const A c; // A is POD, error const B d; // B is not POD, contains data member initializer, no error }