Existem várias dificuldades com os ponteiros:
- Alias A possibilidade de alterar o valor de um objeto usando diferentes nomes / variáveis.
- Não localidade A possibilidade de alterar o valor de um objeto em um contexto diferente daquele em que é declarado (isso também ocorre com argumentos passados por referência).
- Incompatibilidade da vida útil A vida útil de um ponteiro pode ser diferente da vida útil do objeto para o qual ele aponta e pode levar a referências inválidas (SEGFAULTS) ou lixo.
- Aritmética do ponteiro . Algumas linguagens de programação permitem a manipulação de ponteiros como números inteiros, e isso significa que os ponteiros podem apontar para qualquer lugar (incluindo os locais mais inesperados quando um bug está presente). Para usar a aritmética dos ponteiros corretamente, um programador deve estar ciente dos tamanhos de memória dos objetos apontados, e isso é algo mais a se pensar.
- Conversões de tipo A capacidade de converter um ponteiro de um tipo para outro permite substituir a memória de um objeto diferente daquele que se destina.
É por isso que um programador deve pensar mais profundamente ao usar ponteiros (não sei sobre os dois níveis de abstração ). Este é um exemplo dos erros típicos cometidos por um novato:
Pair* make_pair(int a, int b)
{
Pair p;
p.a = a;
p.b = b;
return &p;
}
Observe que códigos como o acima são perfeitamente razoáveis em linguagens que não têm um conceito de ponteiros, mas um nome (referências), objetos e valores, como linguagens de programação funcionais e linguagens com coleta de lixo (Java, Python). .
A dificuldade com funções recursivas ocorre quando pessoas sem formação matemática suficiente (onde a recursividade é comum e requer conhecimento) tentam abordá-las pensando que a função se comportará de maneira diferente dependendo de quantas vezes ela foi chamada anteriormente . Esse problema é agravado porque as funções recursivas podem realmente ser criadas de maneiras pelas quais você precisa pensar dessa maneira para entendê-las.
Pense em funções recursivas com ponteiros sendo distribuídos, como em uma implementação processual de uma Árvore Vermelho-Preta na qual a estrutura de dados é modificada no local; é algo mais difícil de pensar do que uma contraparte funcional .
Não é mencionado na pergunta, mas a outra questão importante com a qual os novatos têm dificuldade é a simultaneidade .
Como outros já mencionaram, há um problema adicional, não conceitual, em algumas construções da linguagem de programação: é que, mesmo que entendamos, erros simples e honestos com essas construções podem ser extremamente difíceis de depurar.