Respostas:
Supondo que esses valores sejam tipos primitivos, então não, não há diferença. As listas de inicialização só fazem diferença quando você tem objetos como membros, pois em vez de usar a inicialização padrão seguida pela atribuição, a lista de inicialização permite inicializar o objeto com seu valor final. Na verdade, isso pode ser visivelmente mais rápido.
Você precisa usar a lista de inicialização para inicializar membros constantes, referências e classe base
Quando você precisa inicializar um membro constante, referências e passar parâmetros para os construtores da classe base, conforme mencionado nos comentários, você precisa usar a lista de inicialização.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Exemplo de classe / estrutura (não exaustiva) contém referência:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
E um exemplo de inicialização de classe base que requer um parâmetro (por exemplo, nenhum construtor padrão):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
_capacity
, _data
e _len
tiver tipos de classe sem construtores padrão acessíveis?
const
membro no corpo do construtor, você deve usar a lista de inicialização - não const
membros podem ser inicializados na lista de inicialização ou no corpo do construtor.
Sim. No primeiro caso, você pode declarar _capacity
, _data
e _len
como constantes:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
Isso seria importante se você quiser garantir a const
-ness dessas variáveis de instância ao calcular seus valores em tempo de execução, por exemplo:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
as instâncias devem ser inicializadas na lista de inicializadores ou os tipos subjacentes devem fornecer construtores públicos sem parâmetros (o que os tipos primitivos fornecem).
Acho que este link http://www.cplusplus.com/forum/articles/17820/ dá uma explicação excelente - especialmente para aqueles que são novos em C ++.
A razão pela qual as listas de inicializadores são mais eficientes é que, dentro do corpo do construtor, apenas as atribuições ocorrem, não a inicialização. Portanto, se você estiver lidando com um tipo não interno, o construtor padrão para esse objeto já foi chamado antes que o corpo do construtor tenha sido inserido. Dentro do corpo do construtor, você está atribuindo um valor a esse objeto.
Na verdade, esta é uma chamada para o construtor padrão seguida por uma chamada para o operador de atribuição de cópia. A lista de inicializadores permite que você chame o construtor de cópia diretamente, e isso às vezes pode ser significativamente mais rápido (lembre-se de que a lista de inicializadores está antes do corpo do construtor)
Acrescentarei que, se você tiver membros do tipo de classe sem nenhum construtor padrão disponível, a inicialização é a única maneira de construir sua classe.
Uma grande diferença é que a atribuição pode inicializar membros de uma classe pai; o inicializador funciona apenas em membros declarados no escopo da classe atual.
A verdadeira diferença se resume em como o compilador gcc gera código de máquina e armazena a memória. Explicar:
Certamente, existem outras maneiras de lidar com membros do tipo const. Mas para facilitar sua vida, os escritores do compilador gcc decidem definir algumas regras
Existe apenas uma maneira de inicializar instâncias de classe base e variáveis de membro não estáticas e é usando a lista de inicializadores.
Se você não especificar uma variável de membro base ou não estática na lista de inicializadores de seu construtor, então esse membro ou base será inicializado por padrão (se o membro / base for um tipo de classe não POD ou array de classe não POD tipos) ou deixados não inicializados.
Uma vez que o corpo do construtor é inserido, todas as bases ou membros terão sido inicializados ou deixados não inicializados (ou seja, eles terão um valor indeterminado). Não há oportunidade no corpo do construtor de influenciar como eles devem ser inicializados.
Você pode atribuir novos valores a membros no corpo do construtor, mas não é possível atribuir a const
membros ou membros do tipo de classe que se tornaram não atribuíveis e não é possível religar referências.
Para tipos integrados e alguns tipos definidos pelo usuário, a atribuição no corpo do construtor pode ter exatamente o mesmo efeito que inicializar com o mesmo valor na lista de inicializadores.
Se você não conseguir nomear um membro ou base em uma lista de inicializadores e essa entidade for uma referência, tiver tipo de classe sem nenhum construtor padrão declarado pelo usuário acessível, for const
qualificado e ter tipo POD ou for um tipo de classe POD ou array do tipo de classe POD contendo um const
membro qualificado (direta ou indiretamente), então o programa está mal formado.
Se você escrever uma lista de inicializadores, fará tudo em uma única etapa; se você não escrever uma lista do initilizer, você fará 2 passos: um para declaração e outro para atribuir o valor.
Há uma diferença entre a lista de inicialização e a instrução de inicialização em um construtor. Vamos considerar o código abaixo:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
Quando MyClass é usado, todos os membros serão inicializados antes da primeira instrução em um construtor executado.
Mas, quando MyClass2 é usado, todos os membros não são inicializados quando a primeira instrução em um construtor é executada.
No caso posterior, pode haver problema de regressão quando alguém adiciona algum código em um construtor antes de um determinado membro ser inicializado.
Aqui está um ponto que não vi outros se referirem a ele:
class temp{
public:
temp(int var);
};
A classe temporária não possui um ctor padrão. Quando o usamos em outra classe, como segue:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
o código não vai compilar, porque o compilador não sabe como inicializar obj
, porque ele tem apenas um ctor explícito que recebe um valor int, então temos que mudar o ctor da seguinte maneira:
mainClass(int sth):obj(sth){}
Portanto, não se trata apenas de const e referências!