Passagem por Valor
Na passagem por valor, o compilador cria uma cópia local do dado original e a armazena em um novo endereço de memória dentro do escopo da função. Quaisquer modificações realizadas no parâmetro afetam apenas essa cópia, preservando a variável original intacta.
Considerações:
- Segurança: Garante que a função não altere o estado da variável externa.
- Desempenho: Para tipos primitivos (como
intoudouble), o custo é desprezível. Contudo, para objetos grandes ou coleções (comostd::vector), a cópia pode gerar um overhead significativo de memória e processamento.
void calcularDobro(int numero) {
numero = numero * 2; // Altera apenas a cópia local
}
int valor = 10;
calcularDobro(valor);
// Após a execução, 'valor' continua sendo 10.
Passagem por Ponteiro (Endereço)
Nesta abordagem, o que é enviado para a função é o endereço de memória da variável original. O parâmetro da função é um ponteiro que aponta para o local onde o dado reside. Através do operador de desreferenciação (*), a função pode acessar e manipular diretamente o valor original.
Considerações:
- Eficiência: Apenas o endereço (geralmente 4 ou 8 bytes) é copiado, independentemente do tamanho do objeto apontado.
- Flexibilidade: Permite passar
nullptrpara indicar a ausência de um valor. - Risco: Exige verificações de segurança para evitar o acesso a ponteiros nulos ou inválidos.
void resetarValor(int* ptr) {
if (ptr != nullptr) {
*ptr = 0; // Modifica o valor no endereço original
}
}
int contador = 50;
resetarValor(&contador);
// O endereço de 'contador' é passado. Agora 'contador' é 0.
Passagem por Referência
A passagem por referência funicona como a criação de um apelido (alias) para a variável original. Embora tecnicamente o compilador use endereços por debaixo dos panos, a sintaxe é idêntica à da passagem por valor, mas sem a criação de cópias dos dados.
Considerações:
- Sintaxe Limpa: Evita o uso excessivo de operadores de ponteiro, tornando o código mais legível.
- Segurança Adicional: Referências não podem ser nulas e devem ser inicializadas obrigatoriamente, o que reduz erros comuns encontrados em ponteiros.
- Const References: O uso de
const T&é uma prática padrão em C++ para passar objetos grandes de forma eficiente, garantindo que eles não sejam modificados acidentalmente.
void adicionarSufixo(std::string& texto) {
texto += "_processado"; // Modifica a string original diretamente
}
std::string log = "dados";
adicionarSufixo(log);
// 'log' agora contém "dados_processado".
Critérios de Escolha
Para otimizar o desenvolvimento em C++, recomenda-se seguir estas diretrizes:
- Tipos Primitivos: Utilize passagem por valor. O custo de copiar um inteiro é muitas vezes menor do que o custo de mainpular endereços de memória.
- Objetos e Estruturas Médias/Grandes:
- Se a função não deve alterar o objeto: use
const T&(referência constante). - Se a função precisa modificar o objeto oriignal: use referência (
T&).
- Se a função não deve alterar o objeto: use
- Opcionalidade: Se o parâmetro for opcional ou se você precisar lidar com lógica de memória de baixo nível, utilize ponteiros para permitir a passagem de
nullptr.