Soy parcial en el uso de listas de inicialización de miembros con mis constructores ... pero hace mucho tiempo que olvidé las razones detrás de esto ...
¿Utiliza listas de inicialización de miembros en sus constructores? Si es así, ¿por qué? ¿Si no, porque no?
c++
oop
object-construction
paxos1977
fuente
fuente
Respuestas:
Para los miembros de la clase POD , no hay diferencia, es solo una cuestión de estilo. Para los miembros de la clase que son clases, evita una llamada innecesaria a un constructor predeterminado. Considerar:
En este caso, el constructor para
B
llamará al constructor predeterminado paraA
, y luego se inicializaráa.x
a 3. Una mejor forma sería queB
el constructor deA
' llame directamente al constructor en la lista de inicializadores:Esto solo llamaría
A
alA(int)
constructor y no al constructor predeterminado. En este ejemplo, la diferencia es insignificante, pero imagine si lo desea,A
el constructor predeterminado hizo más, como asignar memoria o abrir archivos. No querrías hacer eso innecesariamente.Además, si una clase no tiene un constructor predeterminado, o si tiene una
const
variable miembro, debe usar una lista de inicializador:fuente
Además de las razones de rendimiento mencionadas anteriormente, si su clase almacena referencias a objetos pasados como parámetros de constructor o su clase tiene variables constantes, entonces no tiene otra opción que usar listas de inicializador.
fuente
Una razón importante para usar la lista de inicializador de constructor que no se menciona en las respuestas aquí es la inicialización de la clase base.
Según el orden de construcción, la clase base debe construirse antes de la clase secundaria. Sin la lista de inicializador de constructor, esto es posible si su clase base tiene un constructor predeterminado que se llamará justo antes de ingresar el constructor de la clase secundaria.
Pero, si su clase base solo tiene un constructor parametrizado, entonces debe usar la lista de inicializador del constructor para asegurarse de que su clase base se inicialice antes que la clase secundaria.
Inicialización de subobjetos que solo tienen constructores parametrizados
Eficiencia
Usando la lista de inicializador de constructor, inicializa sus miembros de datos al estado exacto que necesita en su código en lugar de inicializarlos primero a su estado predeterminado y luego cambiar su estado al que necesita en su código.
Si los miembros de datos constantes no estáticos de su clase tienen constructores predeterminados y no utiliza la lista de inicializadores de constructores, no podrá inicializarlos al estado deseado, ya que se inicializarán a su estado predeterminado.
Los miembros de datos de referencia deben inicializarse cuando el compilador ingresa al constructor, ya que las referencias no pueden declararse e inicializarse más tarde. Esto solo es posible con la lista de inicializador de constructor.
fuente
Además de los problemas de rendimiento, hay otro muy importante que llamaría mantenibilidad y extensibilidad del código.
Si un T es POD y comienza a preferir la lista de inicialización, si una vez T cambiará a un tipo que no sea POD, no necesitará cambiar nada en torno a la inicialización para evitar llamadas innecesarias al constructor porque ya está optimizado.
Si el tipo T tiene un constructor predeterminado y uno o más constructores definidos por el usuario y una vez que decide eliminar u ocultar el predeterminado, entonces si se utilizó la lista de inicialización, no necesita actualizar el código si sus constructores definidos por el usuario porque ya están implementados correctamente.
Lo mismo con los miembros const o miembros de referencia, digamos que inicialmente T se define de la siguiente manera:
Luego, decide calificar a como constante, si usaría la lista de inicialización desde el principio, entonces este fue un cambio de línea simple, pero tener la T definida como anteriormente, también requiere cavar la definición del constructor para eliminar la asignación:
No es un secreto que el mantenimiento es mucho más fácil y menos propenso a errores si el código fue escrito no por un "código mono" sino por un ingeniero que toma decisiones basadas en una consideración más profunda sobre lo que está haciendo.
fuente
Antes de ejecutar el cuerpo del constructor, se invocan todos los constructores para su clase padre y luego para sus campos. Por defecto, se invocan los constructores sin argumentos. Las listas de inicialización le permiten elegir qué constructor se llama y qué argumentos recibe ese constructor.
Si tiene una referencia o un campo constante, o si una de las clases utilizadas no tiene un constructor predeterminado, debe usar una lista de inicialización.
fuente
Aquí el compilador sigue los siguientes pasos para crear un objeto de tipo MyClass
1. El constructor de tipos se llama primero para "a".
2. El operador de asignación de "Tipo" se llama dentro del cuerpo del constructor MyClass () para asignar
Y, finalmente, el destructor de "Tipo" se llama "a", ya que está fuera de alcance.
Ahora considere el mismo código con el constructor MyClass () con la Lista de inicializadores
Con la Lista de inicializadores, el compilador sigue los siguientes pasos:
fuente
Solo para agregar información adicional para demostrar cuánta diferencia puede marcar la lista de inicialización de miembros . En el Leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/ , donde necesita construir e inicializar a cero un vector con cierto tamaño. Aquí hay dos diferentes implementaciones y comparaciones de velocidad.
Sin la lista de inicialización de miembros , obtener AC me costó unos 212 ms .
Ahora, usando la lista de inicialización de miembros , el tiempo para obtener AC es de aproximadamente 108 ms . Con este simple ejemplo, es bastante obvio que la lista de inicialización de miembros es mucho más eficiente . Toda la medición es del tiempo de ejecución de LC.
fuente
Sintaxis:
Lista de necesidades de inicialización:
en el programa anterior, cuando se ejecuta el constructor de la clase, Sam_x y Sam_y . Luego, en el cuerpo del constructor, se definen las variables de datos de miembros.
Casos de uso:
En C, las variables deben definirse durante la creación. de la misma manera en C ++, debemos inicializar la variable Const y Reference durante la creación de objetos mediante la lista de Inicialización. Si hacemos la inicialización después de la creación del objeto (dentro del cuerpo del constructor), obtendremos un error de tiempo de compilación.
Objetos miembros de la clase Sample1 (base) que no tienen un constructor predeterminado
Al crear un objeto para la clase derivada que internamente llama al constructor de la clase derivada y llama al constructor de la clase base (predeterminado). Si la clase base no tiene un constructor predeterminado, el usuario obtendrá un error de tiempo de compilación. Para evitar, debemos tener
El nombre del parámetro del constructor de la clase y el miembro de datos de una clase son los mismos:
Como todos sabemos, la variable local tiene la más alta prioridad que la variable global si ambas variables tienen el mismo nombre. En este caso, el programa considera el valor "i" {variable del lado izquierdo y derecho. es decir: i = i} como variable local en el constructor Sample3 () y la variable miembro de clase (i) se anuló. Para evitar, debemos usar cualquiera
fuente
Como se explica en las Pautas principales de C ++ C.49: Prefiere la inicialización a la asignación en constructores , evita llamadas innecesarias a constructores predeterminados.
fuente