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 inteiros, mas cria um problema com ponteiros: ambas as structs acabam apontando para a mesma memória.
typedef struct {
char *name;
int age;
} Person;
Person alice = {"Alice", 30};
Person copy = alice; // Cópia rasa!
// Tanto alice.name quanto copy.name apontam para a MESMA string
Se você liberar um deles, o outro se tornará inválido. Se você modificar a string por meio de um deles, ambos verão a alteração. Isso raramente é o que você deseja.
Uma cópia profunda aloca nova memória para os membros ponteiro 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 possui 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 cópia na qual modificar ou liberar o original não tem efeito sobre o clone.
Você criará três arquivos:
student.h: Declare uma structStudentcom 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é a parte principal. Ela deve alocar memória nova tanto para a struct quanto para a string de nome e, em seguida, copiar os dados reais da string (não apenas o endereço do ponteiro). Isso garante que o clone seja totalmente proprietário de sua própria memória, separada da memória do original.main.c: Crie um estudante, clone-o, exiba as informações de ambos os estudantes e, em seguida, limpe corretamente os dois objetos.
Você receberá duas entradas: o nome do estudante (uma string) e a nota (um inteiro).
Em seu 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, e não 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;
// Ler 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: Print the original student's information
// Formato: "Original: {name}, Grade: {grade}"
// TODO: Imprima as informações do clone
// Formato: "Clone: {name}, Grade: {grade}"
// TODO: Liberar ambos os estudantes
// Imprimir 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çalhoInclude GuardsArquivos-FonteFunções EstáticasRecapitulação: Calculadora Modular4Encapsulamento
Conceito de Ponteiros OpacosDefinindo Structs OpacasGetters e SettersValidação em SettersRecapitulação: Caixa Secreta2Objetos e Métodos
Structs como ObjetosO Ponteiro 'Self'Const CorrectnessPonteiro vs ValorMétodos AuxiliaresRecapitulação: Point Manager5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de Vida de Objetos
Padrão de ConstrutorPadrão de DestrutorInicialização na StackCópia ProfundaRecapitulação: String Wrapper6Herança via Composição
Incorporação de StructsA Regra do Primeiro MembroAcessando Membros PaiUpcastingRecapitulação: Hierarquia de Formas9Projeto: Desenhador de Formas
Visão Geral do ProjetoImplementação do CírculoImplementação do RetânguloUso PolimórficoContainer de FormasPratique por conta própria: Compilador de C online