O novo recurso de boot do membro C ++ 11 na declaração tornou listas de boot obsoletas?

Com o C ++ 11, agora temos a capacidade de inicializar os membros da class em uma declaração de header:

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

Então estou um pouco confuso. Tradicionalmente, as listas de boot nos construtores foram usadas para boot do membro:

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

O novo recurso de boot do membro C ++ 11 na declaração tornou listas de boot obsoletas? Se não, quais são as vantagens de uma sobre a outra? Que situações tornariam a boot na declaração vantajosa ou as listas de boot vantajosas? Quando um deve ser usado sobre o outro?

Não, eles não são obsoletos, como diz este artigo Conheça os novos formulários de boot do C ++ 11 na seção Inicialização do Membro da Classe ( ênfase minha ):

Tenha em mente que, se o mesmo membro de dados tiver um inicializador de membro de class e um mem-init no construtor, o último terá precedência. Na verdade, você pode aproveitar esse comportamento especificando um valor padrão para um membro na forma de um inicializador de membro de class que será usado se o construtor não tiver um mem-init explícito para esse membro. Caso contrário, o mem-init do construtor entrará em vigor, sobrescrevendo o inicializador do membro de class. Essa técnica é útil em classs que possuem vários construtores

Portanto, embora a boot do membro da class seja uma boa conveniência, ela não elimina a necessidade de listas de boot, mas ambos os resources funcionam juntos para fornecer uma maneira agradável de especificar valores padrão e substituí-los quando necessário. Isto parece ser também como Bjarne Stroustrup também vê isso, ele diz:

Isso economiza um pouco de digitação, mas os benefícios reais vêm em classs com vários construtores. Geralmente, todos os construtores usam um inicializador comum para um membro:

e fornece um exemplo de membros que possuem um inicializador comum:

 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 }; 

e disse:

O fato de hash_algorithm e s terem um único padrão é perdido na confusão de código e pode facilmente se tornar um problema durante a manutenção. Em vez disso, podemos fatorar a boot dos membros de dados:

 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: desvantagem em C ++ 11

Há uma desvantagem em usar a boot do membro de class em C ++ 11, uma vez que ela torna uma class não-agregada, não podemos mais usar a boot agregada, o que pode ser bastante surpreendente. Este não é o caso em C ++ 14 onde esta restrição foi removida. Veja: Inicialização agregada de C ++ 11 para classs com inicializadores de membros não estáticos para mais detalhes.

Não, eles não são obsoletos.

Listas de boot ainda são o único caminho a percorrer se você precisar de argumentos construtores para inicializar seus alunos.

 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) { ... } }; 

Observe que, se ambos estiverem presentes, o init do construtor entrará em vigor, sobrescrevendo a boot do membro de class, o que é útil para especificar um valor padrão para um membro de class.

A maneira como eu vejo isso, a boot na class é um ehancement de mem-initializer-lists. Em C ++ 03, os membros não listados em uma lista inicializadora de mem eram sempre inicializados por padrão. Isso significa o construtor padrão para classs e nenhuma boot para tipos primitivos.

Inicialização em class simplesmente permite que você especifique seus próprios padrões. Existem duas maneiras de ver isso.

Um: se a maioria / todos os construtores da sua class quiserem fornecer o mesmo valor inicial para um membro, use um inicializador em class para esse membro. Para outros membros, use mem-initializer-lists. É claro que você terá que usá-los sempre que o valor inicial depender dos argumentos do construtor.

O outro: fornece um inicializador em class para todos os membros, exatamente como o construtor padrão de sua class os inicializaria. Então, mem-initializer-lists em construtores não padrão obtêm a semântica de “como ele difere de um object construído por padrão”.

Intereting Posts