Resumo
Uma expressão de C++ pode fazer duas coisas distintas: dar um valor e mudar o estado do programa. x + 1 só dá um valor; x = 7 dá um valor e, além disso, muda x; x++ dá o valor que x tinha e deixa outro em x. Esta aula estuda essa diferença entre o valor e o efeito de uma expressão: a atribuição como expressão, a atribuição composta, o incremento e o decremento nas suas formas prefixa e pós-fixa, e a ordem em que se avaliam as partes de uma expressão, que o padrão fixa só em parte. Daí se segue a pergunta que ordena o resto da aula: o que o padrão promete acerca de um programa. A resposta é um catálogo de quatro graus, do comportamento definido ao indefinido, que reúne todos os casos vistos até aqui e diz, para cada um, o que o detecta (o compilador, o detector, a biblioteca) e o que ninguém detecta.
Objetivos de aprendizagem
- Distinguir o valor de uma expressão do seu efeito colateral em atribuições, incrementos e chamadas.
- Prever o resultado de
x++e++xusados como valor, e rastrear à mão um programa com atribuições compostas. - Reconhecer expressões que modificam duas vezes uma variável, ou que a leem e a modificam, sem uma ordem fixada pelo padrão, e reescrevê-las em instruções separadas.
- Classificar uma construção como definida, definida pela implementação, não especificada ou indefinida, com um exemplo de cada categoria.
- Dizer, para cada comportamento indefinido do catálogo, se o compilador avisa, se o detector ou a biblioteca o detêm, ou se nenhum deles o detecta.
O valor e o efeito
A aula Aritmética estudou a expressão como uma árvore que se reduz a um valor: 2 + 3 * 4 vale 14, e calculá-la não muda nada fora da própria expressão. A aula Relações e lógica fez o mesmo com as condições, cujo valor é true ou false. Ora, há expressões que, além de dar um valor, deixam uma marca no estado do programa: mudam o valor de uma variável, escrevem na tela ou leem da entrada. Essa marca chama-se efeito colateral, ou simplesmente efeito, e a palavra “colateral” não quer dizer que importe menos: em x = 7 o efeito, que x passe a valer 7, é justamente o que se procura.
Se isto é assim, toda expressão deve ser lida com duas perguntas: o que ela dá e o que ela faz. Três exemplos fixam a distinção. count + 1 dá o sucessor de count e não faz nada: count conserva o seu valor. count = 9 dá 9 e faz com que count valha 9. std::println("olá") também é uma expressão, uma chamada a uma função, e o que importa nela é o seu efeito: escrever uma linha. As funções próprias serão estudadas na aula Funções, e ali a distinção reaparecerá: uma função que só calcula o seu resultado é mais fácil de entender e de testar do que uma que, além disso, muda algo fora dela.
Uma instrução como count + 1; é C++ válido: calcula-se o valor e descarta-se, de modo que não serve para nada, e o GCC avisa com -Wunused-value. Uma instrução de expressão tem sentido pelo seu efeito. Daí se segue que as expressões com efeito são as que movem o programa, e também as que exigem cuidado, porque o efeito ocorre em algum momento, e esse momento nem sempre é o que o leitor supõe.
Carregando o conteúdo…