Como inicializar variáveis em C++
Table of Contents
- Inicialização de Variáveis em C++
- Formas de Inicialização
- Comparação e Quando Utilizar Cada Forma
- 1. Inicialização por Lista / Uniforme (int d{7}; e int e{};) — A escolha padrão
- 2. Inicialização por Cópia (int b = 5;) — Tradicional e legível
- 3. Inicialização Direta com Parênteses (int c(6);) — Casos específicos de construtores
- 4. Inicialização por Cópia de Lista (int d = {7};) — Agregados e retorno de funções
- 5. Inicialização Padrão (int a;) — Evitar, exceto por performance ou preenchimento imediato
- Resumo Rápido de Decisão
- Principais Diferenças e Armadilhas
- Boas Práticas em C++ Moderno
- Referência
C++ permite que variáveis sejam inicializadas de diferentes formas. Em C++, inicializar uma variável significa fornecer a ela um valor inicial no momento de sua criação (declaração). Isso é diferente de atribuição, que substitui o valor de um objeto já existente. Embora várias sintaxes pareçam fazer a mesma coisa para tipos primitivos, cada uma tem um propósito e um contexto ideal no C++ moderno: Para tipos simples como A inicialização com chaves Em tipos definidos pelo usuário ( Tentar inicializar um objeto com parênteses vazios é interpretado pelo compilador como a declaração de uma função, e não como uma variável: Ao usar chaves Regra geral (C++ Core Guidelines — ES.23): Prefira a sintaxe com chaves https://www.learncpp.com/cpp-tutorial/variable-assignment-and-initialization/ https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es20-always-initialize-an-object Inicialização de Variáveis em C++
Formas de Inicialização
Forma Nome O que acontece int a;Inicialização padrão (default-initialization) Para variáveis locais de tipos fundamentais ( int, double, ponteiros), não define um valor inicial (contém valor indeterminado). Ler a antes de atribuir algo causa comportamento indefinido (undefined behavior). (Nota: variáveis globais ou static são inicializadas com zero).int b = 5;Inicialização por cópia (copy-initialization) Inicializa b com 5. Apesar do símbolo =, não é uma atribuição posterior, mas parte da declaração.int c(6);Inicialização direta (direct-initialization) Inicializa c com 6 usando parênteses. Em classes, invoca diretamente o construtor correspondente.int d{7};Inicialização direta por lista (direct-list-initialization) Inicializa d com 7 (introduzida no C++11 como inicialização uniforme). Impede conversões de estreitamento (narrowing conversions).int d = {7};Inicialização por cópia de lista (copy-list-initialization) Semelhante a int d{7}; (também proíbe narrowing), mas não considera construtores marcados como explicit.int e{};Inicialização por valor (value-initialization) Para tipos fundamentais como int, realiza zero-initialization (inicializa com 0). Para classes, chama o construtor padrão. Comparação e Quando Utilizar Cada Forma
1. Inicialização por Lista / Uniforme (
int d{7}; e int e{};) — A escolha padrãostructs, classes e contêineres) e proíbe conversões com perda de dados (narrowing conversions).Tipo var{valor}; quando já souber o valor inicial e quiser garantia contra truncamento acidental de dados.Tipo var{}; quando quiser inicializar a variável com um valor padrão seguro (0, nullptr, false ou construtor padrão), evitando lixo de memória e a ambiguidade com declaração de funções (Most Vexing Parse). 2. Inicialização por Cópia (
int b = 5;) — Tradicional e legívelexplicit.int, bool, double) quando a equipe ou base de código prefere a legibilidade tradicional do =.auto (ex.: auto x = 5; ou AAA style — Almost Always Auto), onde o tipo já é determinado diretamente pela expressão à direita. 3. Inicialização Direta com Parênteses (
int c(6);) — Casos específicos de construtoresexplicit), mas permite narrowing conversions e sofre com o Most Vexing Parse se usada sem argumentos (Tipo c();).std::initializer_list e você quer chamar outro construtor específico que não seja o da lista. O exemplo clássico é std::vector<int> v(5, 10); (cria 5 elementos com valor 10), em vez de std::vector<int> v{5, 10}; (cria 2 elementos: 5 e 10). 4. Inicialização por Cópia de Lista (
int d = {7};) — Agregados e retorno de funções= com a segurança das chaves {} contra narrowing, mas não permite chamar construtores explicit.structs agregadas ou arrays de forma clara: Ponto p = {10, 20};.explicit deve ocorrer. 5. Inicialização Padrão (
int a;) — Evitar, exceto por performance ou preenchimento imediatostd::string s;), ela chama o construtor normalmente, mas para tipos fundamentais é uma fonte comum de bugs.int x; std::cin >> x;). Resumo Rápido de Decisão
Situação Forma Recomendada Exemplo Valor inicial conhecido (regra geral) Lista direta {valor}int idade{25};Precisa começar zerado / vazio Valor {}int contador{}; / int* ptr{};Construtor conflita com initializer_listDireta (args)std::vector<int> v(100, 0);Uso com autoCópia = ou {}auto total = calculaTotal();Preenchida por std::cin ou out-paramValor {} (ou padrão se imediato)int entrada{}; std::cin >> entrada; Principais Diferenças e Armadilhas
int, as formas b, c e d resultam no mesmo valor final. Porém, as diferenças tornam-se críticas em três cenários: 1. Conversões de estreitamento (Narrowing Conversions)
{} impede conversões implícitas que possam perder dados em tempo de compilação:int x1 = 3.5; // Compila (com aviso): trunca o valor para 3
int x2(3.5); // Compila (com aviso): trunca o valor para 3
int x3{3.5}; // ERRO de compilação: narrowing conversion de double para int 2. Construtores
explicitclass / struct), a inicialização por cópia (=) não aceita construtores marcados como explicit, enquanto a inicialização direta (() ou {}) os aceita:struct Caixa {
explicit Caixa(int tamanho) {}
};
Caixa c1(10); // OK: inicialização direta
Caixa c2{10}; // OK: inicialização direta por lista
// Caixa c3 = 10; // ERRO: construtor é explicit
// Caixa c4 = {10};// ERRO: copy-list-initialization não aceita explicit 3. Most Vexing Parse (O problema dos parênteses vazios)
int f(); // Declara uma função chamada 'f' que retorna int (NÃO cria uma variável!)
int g{}; // Cria uma variável 'g' inicializada com 0 4. Cuidado com
std::initializer_list{} com tipos da biblioteca padrão que possuem um construtor recebendo std::initializer_list (como std::vector), o compilador dará preferência a esse construtor:#include <vector>
std::vector<int> v1(5, 10); // Cria um vetor com 5 elementos, todos com valor 10
std::vector<int> v2{5, 10}; // Cria um vetor com 2 elementos: {5, 10} Boas Práticas em C++ Moderno
{} (list-initialization).int x{valor}; — evita conversões acidentais com perda de precisão.int x{}; — garante que a variável comece zerada sem risco de lixo de memória ou Most Vexing Parse.auto: prefira auto x = valor; ou auto x{valor}; (com um único elemento a partir do C++17, auto x{5}; deduz int, mas auto x = {5}; deduz std::initializer_list<int>). Referência