Recentemente, comecei a aprender C ++ e, como a maioria das pessoas (de acordo com o que tenho lido), estou tendo dificuldades com indicadores.
Não no sentido tradicional, eu entendo o que são, e por que são usados, e como podem ser úteis; no entanto, não consigo entender como os ponteiros de incremento seriam úteis, alguém pode fornecer uma explicação de como o incremento de um ponteiro é um conceito útil e C ++ idiomático?
Essa pergunta surgiu depois que comecei a ler o livro A Tour of C ++, de Bjarne Stroustrup, fui recomendado por este livro, porque eu conheço bem o Java, e os caras do Reddit me disseram que seria um bom livro de 'troca' .
Respostas:
Quando você tem uma matriz, pode configurar um ponteiro para apontar para um elemento da matriz:
Aqui
p
aponta para o primeiro elemento dea
, que éa[0]
. Agora você pode incrementar o ponteiro para apontar para o próximo elemento:Agora
p
aponta para o segundo elementoa[1]
,. Você pode acessar o elemento aqui usando*p
. Isso é diferente de Java, onde você precisaria usar uma variável de índice inteiro para acessar elementos de uma matriz.Incrementar um ponteiro em C ++ em que esse ponteiro não aponta para um elemento de uma matriz é um comportamento indefinido .
fonte
Incrementar ponteiros é C ++ idiomático, porque a semântica de ponteiros reflete um aspecto fundamental da filosofia de design por trás da biblioteca padrão C ++ (baseada na STL de Alexander Stepanov )
O conceito importante aqui é que o STL é projetado em torno de contêineres, algoritmos e iteradores. Ponteiros são simplesmente iteradores .
Obviamente, a capacidade de incrementar (ou adicionar / subtrair) ponteiros remonta a C. Muitos algoritmos de manipulação de cordas C podem ser escritos simplesmente usando a aritmética dos ponteiros. Considere o seguinte código:
Esse código usa a aritmética do ponteiro para copiar uma cadeia C terminada em nulo. O loop termina automaticamente quando encontra o nulo.
Com o C ++, a semântica do ponteiro é generalizada para o conceito de iteradores . A maioria dos contêineres C ++ padrão fornece iteradores, que podem ser acessados através das funções-membro
begin
eend
. Os iteradores se comportam como ponteiros, pois podem ser incrementados, desreferenciados e, às vezes, decrementados ou avançados.Para iterar sobre um
std::string
, diríamos:Nós incrementamos o iterador da mesma forma que incrementamos um ponteiro para uma string C simples. A razão pela qual esse conceito é poderoso é porque você pode usar modelos para escrever funções que funcionarão para qualquer tipo de iterador que atenda aos requisitos de conceito necessários. E este é o poder do STL:
Este código copia uma string em um vetor. A
copy
função é um modelo que funcionará com qualquer iterador que ofereça suporte ao incremento (que inclui ponteiros simples). Poderíamos usar a mesmacopy
função em uma string C simples:Poderíamos usar
copy
em umstd::map
ou umstd::set
ou qualquer contêiner personalizado que suporte iteradores.Observe que os ponteiros são um tipo específico de iterador: iterador de acesso aleatório , o que significa que eles oferecem suporte para incrementar, decrementar e avançar com o operador
+
e-
. Outros tipos de iteradores suportam apenas um subconjunto de semânticas de ponteiros: um iterador bidirecional suporta pelo menos incrementos e decrementos; um iterador direto suporta pelo menos incrementos. (Todos os tipos de iteradores suportam a desreferenciação.) Acopy
função requer um iterador que suporte pelo menos o incremento.Você pode ler sobre diferentes conceitos de iteradores aqui .
Portanto, incrementar ponteiros é uma maneira idiomática do C ++ para iterar em um array C ou acessar elementos / deslocamentos em um array C.
fonte
A aritmética de ponteiro está em C ++ porque estava em C. A aritmética de ponteiro está em C porque é um idioma normal no assembler .
Existem muitos sistemas em que o "incremento de registro" é mais rápido que "carrega o valor constante 1 e adiciona ao registro". Além disso, muitos sistemas permitem que você "carregue DWORD em A do endereço especificado no registro B e adicione sizeof (DWORD) a B" em uma única instrução. Atualmente, você pode esperar que um compilador otimizador resolva isso para você, mas isso não era realmente uma opção em 1973.
Esta é basicamente a mesma razão pela qual as matrizes C não são verificadas por limites e as seqüências C não têm um tamanho incorporado: a linguagem foi desenvolvida em um sistema em que cada byte e cada instrução contavam.
fonte