¿Ha quedado obsoleta la nueva característica de inicialización de miembros de C ++ 11 en las listas de inicialización de declaraciones declaradas?

Con C ++ 11, ahora tenemos la capacidad de inicializar los miembros de la clase en una statement de encabezado:

class aClass { private: int mInt{100}; public: aClass(); ~aClass(); }; 

Entonces estoy un poco confundido. Tradicionalmente, las listas de inicialización en constructores se han utilizado para la inicialización de miembros:

 aClass::aClass() : mInt(100) { ... } 

¿Ha quedado obsoleta la nueva característica de inicialización de miembros de C ++ 11 en las listas de inicialización de declaraciones declaradas? Si no, ¿cuáles son las ventajas de una sobre la otra? ¿Qué situaciones harían ventajosa la inicialización en la statement, o las listas de inicialización serían ventajosas? ¿Cuándo se debe usar uno sobre el otro?

No, no son obsoletos ya que este artículo Conoce los nuevos formularios de inicialización de C ++ 11 en la sección Inicialización de miembros de la clase ( énfasis mío ):

Tenga en cuenta que si el mismo miembro de datos tiene un inicializador miembro de clase y un mem-init en el constructor, este último tiene prioridad. De hecho, puede aprovechar este comportamiento especificando un valor predeterminado para un miembro en forma de un inicializador de miembro de clase que se usará si el constructor no tiene una mem-init explícita para ese miembro. De lo contrario, la mem-init del constructor tendrá efecto, anulando el inicializador de miembro de la clase. Esta técnica es útil en clases que tienen múltiples constructores

Así que, aunque en la inicialización de miembros de la clase es una buena conveniencia, no elimina la necesidad de listas de inicialización, pero ambas funciones en su lugar trabajan juntas para brindarle una buena manera de especificar valores predeterminados y anularlos cuando sea necesario. Esta parece ser también la forma en que Bjarne Stroustrup también lo ve, él dice:

Esto ahorra un poco de tipeo, pero los beneficios reales vienen en clases con múltiples constructores. A menudo, todos los constructores usan un inicializador común para un miembro:

y proporciona un ejemplo de miembros que tienen un inicializador común:

 class A { public: A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {} A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {} A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {} int a, b; private: HashingFunction hash_algorithm; // Cryptographic hash to be applied to all A instances std::string s; // String indicating state in object lifecycle }; 

y dice:

El hecho de que hash_algorithm ys tengan un único valor predeterminado se pierde en el desorden del código y podría convertirse fácilmente en un problema durante el mantenimiento. En cambio, podemos factorizar la inicialización de los miembros de datos:

 class A { public: A(): a(7), b(5) {} A(int a_val) : a(a_val), b(5) {} A(D d) : a(7), b(g(d)) {} int a, b; private: HashingFunction hash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A instances std::string s{"Constructor run"}; // String indicating state in object lifecycle }; 

Nota: desventaja en C ++ 11

La utilización de la inicialización de miembros de clase en C ++ 11 tiene una desventaja, ya que hace que una clase no agregue, ya no podemos usar la inicialización agregada, lo que puede ser bastante sorprendente. Este no es el caso en C ++ 14 donde esta restricción fue eliminada. Consulte: Inicialización agregada de C ++ 11 para las clases con inicializadores de miembros no estáticos para obtener más detalles.

No, no están obsoletos.

Las listas de inicialización siguen siendo el único camino a seguir si necesita argumentos de los constructores para inicializar los miembros de su clase.

 class A { int a=7; //fine, give a default value public: A(); }; class B { int b; public: B(int arg) : b(arg) {} B(int arg, bool b) : b(arg) { ... } }; 

Tenga en cuenta que si ambos están presentes, el init del constructor tendrá efecto, anulando la inicialización del miembro de la clase, que es útil para especificar un valor predeterminado para un miembro de la clase.

Tal como lo veo, la inicialización en clase es una mejora de las listas de inicializadores de mem. En C ++ 03, los miembros que no figuran en una lista de inicializadores de mem siempre se inicializaron por defecto. Esto significa el constructor predeterminado para las clases y ninguna inicialización para los tipos primitivos.

La inicialización en clase simplemente le permite especificar sus propios valores predeterminados. Hay dos formas de verlo.

Uno: si la mayoría o todos los constructores de su clase desean proporcionar el mismo valor inicial para un miembro, use un inicializador en clase para ese miembro. Para otros miembros, use mem-initializer-lists. Por supuesto, tendrá que usarlos siempre que el valor inicial dependa de los argumentos del constructor.

El otro: proporcionar un inicializador en clase para todos los miembros, exactamente cómo el constructor predeterminado de su clase los inicializaría. Luego, las listas de inicializadores de mem en constructores no predeterminados obtienen la semántica de “cómo difiere de un objeto construido por defecto”.