Cópia profunda
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 15 de 61.
Quando você atribui uma struct a outra em C, obtém uma cópia superficial: todos os campos são copiados byte a byte. Isso funciona bem para valores simples, como números inteiros, mas cria um problema com ponteiros: as duas structs acabam apontando para a mesma memória.
typedef struct {
char *name;
int age;
} Person;
Person alice = {"Alice", 30};
Person copy = alice; // Cópia superficial!
// alice.name e copy.name apontam para a MESMA string
Se você liberar um deles, o outro se torna inválido. Se você modificar a string por meio de um deles, ambos verão a alteração. Raramente é isso que você quer.
Uma cópia profunda aloca nova memória para os membros ponteiros e copia os dados reais:
Person *clone_person(const Person *original) {
Person *copy = malloc(sizeof(Person));
copy->name = malloc(strlen(original->name) + 1);
strcpy(copy->name, original->name);
copy->age = original->age;
return copy;
}
Agora cada objeto é dono da sua própria string. Você pode modificar ou liberar uma sem afetar a outra. O padrão é simples: para cada membro ponteiro, aloque memória nova e copie o conteúdo, não apenas o endereço.
Desafio
FácilVamos criar um módulo Student que demonstra o padrão de cópia profunda. Você criará uma função de clonagem que produz uma cópia completamente independente de um objeto estudante: uma em que modificar ou liberar o original não afeta o clone.
Você criará três arquivos:
student.h: Declare uma estruturaStudentcom dois membros:char *name(uma string alocada dinamicamente) eint grade. Declare três funções:create_student: construtor que recebe um nome e uma nota e retorna um ponteiro para um novo Studentclone_student: recebe umconst Student *e retorna um ponteiro para uma cópia nova e independentefree_student: destrutor que libera corretamente toda a memória alocada
STUDENT_H.student.c: Implemente as três funções. Sua funçãoclone_studenté fundamental. Ela deve alocar memória nova tanto para a estrutura quanto para a string do nome e, em seguida, copiar os dados reais da string (não apenas o endereço do ponteiro). Isso garante que o clone seja dono de sua própria memória, completamente separada da memória do original.main.c: Crie um estudante, clone-o, exiba as informações dos dois estudantes e, em seguida, limpe corretamente os dois objetos.
Você receberá duas entradas: o nome do estudante (uma string) e a nota (um inteiro).
No arquivo principal, crie um estudante com os valores fornecidos e, em seguida, crie um clone desse estudante. Imprima as informações do original e do clone para verificar se eles contêm os mesmos dados. Por fim, libere os dois estudantes e imprima uma confirmação.
Imprima a saída neste formato:
Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freedPor exemplo, com as entradas Alice e 95, a saída seria:
Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freedO padrão de cópia profunda garante que cada objeto seja realmente independente: o clone tem sua própria string alocada, em vez de um ponteiro compartilhado para a memória do original.
Experimente você mesmo
#include <stdio.h>
#include <stdlib.h>
#include "student.h"
int main() {
char name[100];
int grade;
// Leia a entrada
scanf("%s", name);
scanf("%d", &grade);
// TODO: Crie um estudante com o nome e a nota fornecidos
// TODO: Crie um clone do estudante
// TODO: Imprima as informações do estudante original
// Formato: "Original: {name}, Grade: {grade}"
// TODO: Imprima as informações do clone
// Formato: "Clone: {name}, Grade: {grade}"
// TODO: Libere a memória de ambos os estudantes
// Imprima a confirmação
printf("Both freed\n");
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos da Programação Modular
Arquivos de cabeçalhoProteções de inclusãoArquivos-fonteFunções estáticasRevisão: calculadora modular4Encapsulamento
Conceito de ponteiros opacosDefinindo structs opacasGetters e settersValidação em settersRevisão: caixa secreta2Objetos e métodos
Structs como objetosO ponteiro 'Self'Correção de constPonteiro vs. valorMétodos auxiliaresRevisão: Gerenciador de pontos5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de vida do objeto
Padrão de construtorPadrão de destrutorInicialização da pilhaCópia profundaRevisão: wrapper de String6Herança por composição
Incorporação de structRegra do primeiro membroAcessando membros do tipo paiUpcastingRevisão: hierarquia de formas9Projeto: Desenhador de Formas
Visão geral do projetoImplementação do círculoImplementação do retânguloUso polimórficoContêiner de formasPratique por conta própria: Compilador de C online