Resumo
Até aqui, cada coleção do curso guardava dados de um só tipo: notas, estaturas, posições de uma tabela. As entidades de um problema, por outro lado, têm vários atributos de tipos diferentes: um estudante tem um nome e uma nota; um livro, um título, um autor e um ano. Esta aula apresenta o registro, o tipo composto que o próprio programador define com struct para agrupar esses atributos sob um só nome. Começa pela razão de ser do registro, a fragilidade dos vetores paralelos; segue com a definição de um struct, seus campos com valor inicial e a criação de registros com chaves e com inicializadores designados; depois, os registros como parâmetros e como resultados de funções; os vetores de registros, que se percorrem com vinculações estruturadas e se ordenam e se buscam por um campo, com a questão da ordenação estável; e termina com a arte de modelar um problema com tipos que reflitam o seu domínio.
Objetivos de aprendizagem
- Definir um
structcom campos e valores iniciais, e criar registros com inicialização com chaves, também com inicializadores designados. - Escrever funções que recebam e devolvam registros, escolhendo o modo de passagem.
- Ordenar e buscar em um vetor de registros por um campo com
std::ranges::sort,std::ranges::stable_sortestd::ranges::findcom uma projeção, e distinguir uma ordenação estável de uma que não o é. - Modelar com registros os dados de um problema e justificar que campos e tipos se escolhem.
Agrupar dados
Vetores paralelos
Suponha-se que um programa deve guardar, para cada estudante de uma turma, o seu nome, a sua nota e a sua idade. Com o que se viu até a aula Tabelas, a solução à mão são três vetores, um por atributo, com a convenção de que o índice designa a mesma pessoa nos três: names[i], grades[i] e ages[i]. Chamam-se vetores paralelos. Uma tabela não serve, porque as suas posições devem ser todas do mesmo tipo, e um nome não é um número.
#include <algorithm>#include <cstddef>#include <print>#include <string>#include <vector>int main(){ const std::vector<std::string> names{"Ana", "Luis", "Eva"}; std::vector<int> grades{6, 4, 7}; const std::vector<int> ages{19, 22, 20}; std::ranges::sort(grades); for (std::size_t i{0}; i < names.size(); ++i) { std::println("{}: nota {}, {} anos", names[i], grades[i], ages[i]); }}Ana: nota 4, 19 anosLuis: nota 6, 22 anosEva: nota 7, 20 anosO programa queria ordenar os estudantes por nota, e ordenou só as notas. Compila sem avisos, e nem o detector de erros de memória, AddressSanitizer, nem o de comportamento indefinido, UndefinedBehaviorSanitizer, têm nada a relatar; no entanto, a sua saída é falsa: Ana tinha um 6 e aparece com um 4. A convenção que unia os três vetores não está escrita em nenhum lugar que o compilador possa ler, de modo que nada impede rompê-la. Daí se segue a fragilidade dos vetores paralelos: toda operação que mova, acrescente ou retire um elemento deve repetir-se, igual e na mesma ordem, em todos eles; e basta esquecer um para corromper os dados em silêncio.
Três vetores paralelos diante de um vetor de fichas, cada uma com os três dados de uma pessoa.
Demonstração
A coluna 0 descreve uma pessoa:
names[0],grades[0]eages[0]são o nome, a nota e a idade de Ana. O vínculo é só o índice.std::ranges::sort(grades)reordena uma só linha. As outras duas não ficam sabendo: a coluna 0 junta agora o nome de Ana, a nota de Luis e a idade de Ana, que não são de ninguém.A alternativa: um só vetor, cujos elementos são fichas. Cada ficha contém os três dados de uma pessoa, e o vínculo entre eles já não é uma convenção sobre índices, mas a própria ficha.
Ordenar por nota move fichas inteiras: a de Luis passa ao primeiro lugar com o nome e a idade que traz. Nenhum dado pode separar-se dos demais, porque a operação não os vê separadamente.
Se isto é assim, o que o problema pede é um tipo cujos valores sejam fichas: um valor que contenha um nome, uma nota e uma idade, e que se copie, se passe a uma função, se guarde em um vetor e se ordene como um todo. C++ não o traz pronto, porque as fichas de cada problema são diferentes; mas permite que o programador o defina. Esse tipo é o registro.
Carregando o conteúdo…