C++ ++ e --

Somar 1 numa variável é, provavelmente, a conta mais feita em programação: contar visitas, passar para a próxima senha da fila, andar para o próximo item de uma lista, ganhar uma vida no jogo. É tão comum que tem um operador só para isso, o ++, e o seu irmão que subtrai 1, o --. A própria linguagem tem esse nome por causa dele: C++ é "o C, mais um passo". Nesta aula você vai usar os dois, entender a diferença entre ++x e x++, e ver por que algumas combinações são proibidas pelo bom senso (e pelo compilador).

Você vai aprender
  • O que ++ (incremento) e -- (decremento) fazem.
  • A diferença entre pré (++x) e pós (x++): quando o valor muda e qual valor é entregue.
  • Onde eles aparecem mais: no laço for.
  • Em que tipos funcionam, e os erros com bool, const e números.
  • Por que i = i++ e i++ + i++ são armadilhas, e o aviso -Wsequence-point.

Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cpp, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa.


A ideia: o contador de pessoas da portaria

Sabe aquele contador de mão, de metal, que o segurança aperta a cada pessoa que entra no show? Cada clique soma exatamente 1. Ele não serve para somar 5 de uma vez, só para "mais um". O ++ é esse contador. O -- é o mesmo contador apertado ao contrário, quando alguém sai.

EscritoFaz o mesmo queNome
++x; ou x++;x += 1; ou x = x + 1;Incremento
--x; ou x--;x -= 1; ou x = x - 1;Decremento

Os sinais são dois + (ou dois -) grudados, e ficam grudados na variável, antes ou depois dela. O += da tabela vem da aula Operadores de Atribuição.


1. Somar e subtrair 1

#include <iostream>

int main() {
    int vidas = 3;
    ++vidas;
    std::cout << vidas << '\n';
    vidas++;
    std::cout << vidas << '\n';
    --vidas;
    std::cout << vidas << '\n';
    vidas--;
    std::cout << vidas << '\n';
}
$ g++ -std=c++23 -Wall -Wextra incremento.cpp -o incremento
$ ./incremento
4        « ++vidas: 3 + 1
5        « vidas++: 4 + 1
4        « --vidas: 5 - 1
3        « vidas--: 4 - 1

Quando o ++ ou o -- está sozinho na linha, como aqui, tanto faz escrever antes ou depois da variável: ++vidas; e vidas++; fazem exatamente a mesma coisa. A diferença só aparece quando o resultado é usado na mesma linha, como você vai ver agora.


2. Pré × pós: ++x e x++

Além de mudar a variável, o ++ entrega um valor, que pode ser guardado ou mostrado. E aí as duas formas se separam:

  • Pré-incremento, ++x (o ++ vem antes): primeiro soma, depois entrega o valor novo.
  • Pós-incremento, x++ (o ++ vem depois): entrega o valor antigo, e soma depois.
#include <iostream>

int main() {
    int a = 5;
    int b = ++a;    // pré: soma primeiro, depois entrega
    std::cout << "a = " << a << ", b = " << b << '\n';

    int c = 5;
    int d = c++;    // pós: entrega o valor antigo, depois soma
    std::cout << "c = " << c << ", d = " << d << '\n';
}
$ g++ -std=c++23 -Wall -Wextra prepos.cpp -o prepos
$ ./prepos
a = 6, b = 6     « ++a: o a virou 6 e o b recebeu o 6 novo
c = 6, d = 5     « c++: o d recebeu o 5 antigo, e o c virou 6 do mesmo jeito

Repare: nos dois casos a variável terminou com 6. O que muda é só o valor entregue para quem estava esperando (b e d).

Com x = 5Valor entreguex depoisLeia como
++x66"some e me dê"
x++56"me dê e some"
--x44"subtraia e me dê"
x--54"me dê e subtraia"

Um truque para lembrar: leia da esquerda para a direita. Em ++x, você encontra primeiro o ++ (soma) e depois o x (entrega). Em x++, encontra primeiro o x (entrega) e depois o ++ (soma).

A fila de senhas

O pós-incremento combina com a ideia de "chamar e avançar". Na fila do banco, o painel mostra a senha atual e já prepara a próxima:

#include <iostream>

int main() {
    int senha = 100;
    std::cout << senha++ << '\n';
    std::cout << senha << '\n';
    std::cout << ++senha << '\n';
    std::cout << senha-- << '\n';
    std::cout << --senha << '\n';
}
$ g++ -std=c++23 -Wall -Wextra prepos2.cpp -o prepos2
$ ./prepos2
100      « senha++ mostra 100 e a senha vira 101
101      « confirmando
102      « ++senha: vira 102 e mostra 102
102      « senha-- mostra 102 e a senha vira 101
100      « --senha: vira 100 e mostra 100

Experimente: antes de rodar, escreva num papel o que você acha que cada linha vai mostrar. Depois rode e confira. Troque x++ por ++x na primeira linha e veja o que muda.

#include <iostream>

int main() {
    int x = 10;
    int y = x++;
    std::cout << "x = " << x << ", y = " << y << '\n';
    int z = --x;
    std::cout << "x = " << x << ", z = " << z << '\n';
}
Na dúvida, use sozinho na linha

Misturar ++ com outras coisas na mesma linha economiza uma linha, mas obriga quem lê a pensar em "antes ou depois". std::cout << senha << '\n'; ++senha; é mais claro que std::cout << senha++ << '\n';. E quando estiver sozinho, prefira o pré (++x): com int não faz diferença, mas com tipos mais complexos que você verá depois (como os iteradores), o pós precisa guardar uma cópia do valor antigo, e o pré não.


3. No laço for

O lugar onde você mais vai ver ++ e -- é a terceira parte do for, o laço que repete um bloco contando (aula for). Ali, o valor entregue não é usado, então ++i e i++ dão o mesmo resultado:

#include <iostream>

int main() {
    for (int i = 1; i <= 3; ++i) {
        std::cout << "Volta " << i << '\n';
    }
    for (int i = 3; i >= 1; i--) {
        std::cout << i << "... ";
    }
    std::cout << "Já!\n";
}
$ g++ -std=c++23 -Wall -Wextra contagem.cpp -o contagem
$ ./contagem
Volta 1
Volta 2
Volta 3
3... 2... 1... Já!
for (int i = 1; i <= 3; ++i)
"Comece com i = 1; enquanto i <= 3, repita; depois de cada volta, ++i." O ++i é o que faz a contagem andar.
for (int i = 3; i >= 1; i--)
Contagem regressiva: começa em 3 e o i-- desce de 1 em 1.

Esqueceu o ++? O i nunca muda, a condição nunca fica falsa, e o laço roda para sempre. Os detalhes estão na aula for.


4. Em que tipos funcionam

O ++ e o -- funcionam com todos os tipos de número, inclusive double (soma 1.0) e char (vai para o próximo caractere da tabela):

#include <iostream>

int main() {
    double temperatura = 21.5;
    temperatura++;
    std::cout << temperatura << '\n';
    char letra = 'a';
    letra++;
    std::cout << letra << '\n';
}
$ g++ -std=c++23 -Wall -Wextra doubleinc.cpp -o doubleinc
$ ./doubleinc
22.5
b        « 'a' (97) + 1 = 'b' (98)

Mas há três coisas em que eles não funcionam:

bool: proibido desde o C++17

$ g++ -std=c++23 -Wall -Wextra boolinc.cpp -o boolinc
boolinc.cpp: In function ‘int main()’:
boolinc.cpp:3:5: error: use of an operand of type ‘bool’ in ‘operator++’ is forbidden in C++17
    3 |     ligado++;
      |     ^~~~~~

"O uso de um operando do tipo bool no operator++ é proibido no C++17." Antigamente, ligado++ transformava false em true, mas isso confundia mais do que ajudava e foi removido. Para ligar, escreva ligado = true;; para inverter, ligado = !ligado; (veja Operadores Lógicos).

Constantes

$ g++ -std=c++23 -Wall -Wextra consti.cpp -o consti
consti.cpp: In function ‘int main()’:
consti.cpp:3:5: error: decrement of read-only variable ‘vidas’
    3 |     vidas--;
      |     ^~~~~

"Decremento de variável somente leitura." vidas foi criada como const int vidas = 3; (aula Constantes), e nada pode mudá-la.

Números escritos direto

$ g++ -std=c++23 -Wall -Wextra literal.cpp -o literal
literal.cpp: In function ‘int main()’:
literal.cpp:2:13: error: lvalue required as increment operand
    2 |     int x = 5++;
      |             ^
literal.cpp:2:9: warning: unused variable ‘x’ [-Wunused-variable]
    2 |     int x = 5++;
      |         ^

"É necessário um lvalue como operando do incremento": o ++ precisa de um lugar para guardar o resultado, ou seja, uma variável. O 5 não é um lugar (o mesmo erro da aula de atribuição, com 10 = estoque). Se você queria 6, escreva 5 + 1. O aviso de baixo é consequência: como a linha deu erro, o x nunca foi usado.


5. A armadilha: mudar e usar a mesma variável na mesma conta

O ++ faz duas coisas ao mesmo tempo: entrega um valor e muda a variável. Se a mesma variável aparece mais de uma vez na mesma expressão, e alguma dessas aparições a muda, surge a pergunta: em que ordem as coisas acontecem? Às vezes a regra do C++ não responde, e aí o programa tem comportamento indefinido: o compilador pode fazer qualquer coisa (aula Comportamento Indefinido).

i++ + i++: indefinido

#include <iostream>

int main() {
    int i = 5;
    int r = i++ + i++;
    std::cout << r << ' ' << i << '\n';
}
$ g++ -std=c++23 -Wall -Wextra ub2.cpp -o ub2
ub2.cpp: In function ‘int main()’:
ub2.cpp:5:14: warning: operation on ‘i’ may be undefined [-Wsequence-point]
    5 |     int r = i++ + i++;
      |             ~^~
$ ./ub2
11 7

"A operação em i pode ser indefinida." O C++ não diz qual dos dois i++ é feito primeiro, nem quando cada um guarda o resultado. O g++ escolheu um jeito e deu 11 (5 + 6); outro compilador, ou o mesmo com outras opções, pode dar outra coisa, e isso é permitido pela regra. O nome do aviso, -Wsequence-point ("ponto de sequência"), vem dos antigos "pontos" em que o C e o C++ garantiam que tudo antes já tinha acontecido. Ele faz parte do -Wall. No editor do guia, o Clang avisa assim: multiple unsequenced modifications to 'i' [-Wunsequenced], "várias modificações sem ordem definida em i".

i = i++: não faça

Uma tentativa comum de quem começa: "quero somar 1 no i, então i = i++". Veja:

#include <iostream>

int main() {
    int i = 5;
    i = i++;
    std::cout << i << '\n';
}
$ g++ -std=c++23 -Wall -Wextra ub.cpp -o ub
ub.cpp: In function ‘int main()’:
ub.cpp:5:7: warning: operation on ‘i’ may be undefined [-Wsequence-point]
    5 |     i = i++;
      |     ~~^~~~~
ub.cpp:5:7: warning: operation on ‘i’ may be undefined [-Wsequence-point]
$ ./ub
5        « não somou nada!

O i continuou 5. Até o C++14, essa linha era comportamento indefinido, como a anterior. O C++17 criou uma regra para ela: o lado direito do = é resolvido inteiro antes da atribuição. Então:

  1. i++ entrega o valor antigo, 5, e muda i para 6.
  2. A atribuição guarda o 5 entregue em i, por cima do 6.
  3. Resultado: i volta a ser 5. O ++ foi desperdiçado.

Ou seja: no C++ de hoje ela não é mais indefinida, mas é inútil, e em código C++14 ou mais antigo é indefinida. O g++ 15 continua avisando, mesmo com -std=c++23 (o Clang 21 só avisa se você pedir -std=c++14). Seja qual for a versão, a resposta é a mesma: não escreva isso. Para somar 1, basta ++i; (ou i++;, ou i += 1;), sozinho.

A regra prática

Numa mesma expressão, se uma variável é mudada (++, --, =, +=…), não use essa variável de novo. Separe em linhas. Assim você nunca precisa saber as regras finas de ordem, e o código fica mais fácil de ler. E nunca ignore o aviso may be undefined.

Experimente: rode e leia o aviso do compilador na linha do r. Depois reescreva em três linhas sem ambiguidade: some o i ao r, faça ++i, some de novo. O aviso deve sumir.

#include <iostream>

int main() {
    int i = 5;
    int r = i++ + i++;
    std::cout << "r = " << r << ", i = " << i << '\n';
}

Formas diferentes: qual usar

Para somar 1 em xQuando usar
++x;O padrão: sozinho na linha e no for.
x++;Igual ao ++x quando sozinho. Muito comum também; é questão de estilo.
x += 1;Quando o passo pode mudar depois (x += 2).
x = x + 1;A forma mais longa; útil para quem está começando a ler código.
y = x++; / y = ++x;Só quando você quer mesmo o valor antigo/novo, e a linha fica clara.
x = x++;, x++ + x++Nunca.

Quando dá errado

warning: operation on ‘i’ may be undefined [-Wsequence-point]

O que aconteceu: a mesma variável é mudada e usada (ou mudada duas vezes) numa expressão só, como i = i++ ou i++ + i++.

Como resolver: separe em linhas, uma mudança por linha. Para simplesmente somar 1, ++i;.

error: use of an operand of type ‘bool’ in ‘operator++’ is forbidden in C++17

O que aconteceu: ++ ou -- numa variável bool.

Como resolver: atribua o valor que você quer: ligado = true;, ou inverta: ligado = !ligado;.

error: lvalue required as increment operand

O que aconteceu: o ++ foi aplicado a algo que não é uma variável: um número (5++) ou uma conta ((a + b)++).

Como resolver: use + 1 para calcular sem mudar nada, ou aplique o ++ numa variável.

O valor saiu "um a menos" (ou "um a mais") do que o esperado

O que aconteceu: você usou o pós (x++) onde queria o valor novo, ou o pré (++x) onde queria o antigo.

Como resolver: separe: faça o ++x; numa linha e use o x na outra, na ordem que você quer.


Referência

OperadorMuda x paraEntregaFunciona com
++xx + 1o valor novointeiros, double, char (não bool, não const)
x++x + 1o valor antigoidem
--xx - 1o valor novoidem
x--x - 1o valor antigoidem

Exercícios

1. Pós-incremento

int a = 7; e depois int b = a++;. Quanto vale b?

2. Pré-decremento

int a = 7; e depois int b = --a;. Quanto vale b?

3. Contagem regressiva

Complete o for para contar de 10 até 1, descendo de 1 em 1:

for (int i = 10; i >= 1; )

4. int x = 3; e depois int y = x++ * 2;. Quanto valem x e y?

5. Qual destas linhas é a forma recomendada de somar 1 em i?

6. bool ativo = false; O que acontece com ativo++; compilando com -std=c++23?

Missão final: o painel de senhas

Missão: o painel precisa chamar duas senhas seguidas e mostrar qual é a próxima. Use ++ (pré ou pós, onde quiser) para a saída ficar assim:

Chamando a senha 41
Chamando a senha 42
Próxima: 43
#include <iostream>

int main() {
    int senha = 41;
    std::cout << "Chamando a senha " << senha << '\n';
    std::cout << "Chamando a senha " << senha << '\n';
    std::cout << "Próxima: " << senha << '\n';
}
#include <iostream>

int main() {
    int senha = 41;
    std::cout << "Chamando a senha " << senha << '\n';
    ++senha;
    std::cout << "Chamando a senha " << senha << '\n';
    ++senha;
    std::cout << "Próxima: " << senha << '\n';
}

Resumo

  • ++x / x++ somam 1; --x / x-- subtraem 1.
  • Sozinhos na linha, pré e pós são iguais. Dentro de uma expressão: ++x entrega o valor novo; x++ entrega o antigo. A variável muda nos dois casos.
  • O uso mais comum é no for: for (int i = 0; i < n; ++i).
  • Funcionam com inteiros, double e char. Não funcionam com bool (proibido desde o C++17), com const nem com números escritos direto.
  • Não mude e use a mesma variável na mesma expressão: i++ + i++ é comportamento indefinido, e i = i++ é indefinido até o C++14 e inútil depois. O g++ avisa com -Wsequence-point.