Fácil C++

Implemente o construtor de cópia

Enunciado

Complete a classe String para que o construtor de cópia faça uma cópia profunda da string alocada dinamicamente. O programa deve imprimir o conteúdo das duas strings e não deve causar double free.

Requisitos

  • O construtor de cópia aloca nova memória e copia o conteúdo.
  • O destrutor libera a memória corretamente.
  • A saída mostra as duas strings iguais.

Código inicial

#include <iostream>
#include <cstring>

class String {
    char* data_;
public:
    String(const char* s) {
        data_ = new char[std::strlen(s) + 1];
        std::strcpy(data_, s);
    }
    // TODO: construtor de cópia
    ~String() { delete[] data_; }
    const char* c_str() const { return data_; }
};

int main() {
    String a("hello");
    String b = a;
    std::cout << a.c_str() << " " << b.c_str() << "\n";
    return 0;
}

Saída esperada

hello hello
Ver dica

No construtor de cópia, aloque new char[std::strlen(other.data_) + 1] e copie com std::strcpy.

Mostrar solução
#include <iostream>
#include <cstring>

class String {
    char* data_;
public:
    String(const char* s) {
        data_ = new char[std::strlen(s) + 1];
        std::strcpy(data_, s);
    }

    // Construtor de cópia: cópia profunda
    String(const String& other) {
        data_ = new char[std::strlen(other.data_) + 1];
        std::strcpy(data_, other.data_);
    }

    ~String() { delete[] data_; }
    const char* c_str() const { return data_; }
};

int main() {
    String a("hello");
    String b = a;
    std::cout << a.c_str() << " " << b.c_str() << "\n";
    return 0;
}

Passo a passo

  1. A classe String guarda um ponteiro char* data_ para uma string alocada dinamicamente.
  2. O construtor comum aloca memória e copia o literal.
  3. O construtor de cópia recebe const String& other e aloca um novo buffer do mesmo tamanho.
  4. Em seguida, copia o conteúdo com std::strcpy, garantindo que cada objeto tenha sua própria memória.
  5. O destrutor libera a memória de cada objeto independentemente.
  6. No main, String b = a; chama o construtor de cópia, criando uma cópia profunda.

Por que funciona

Sem o construtor de cópia, o compilador geraria uma cópia superficial que apenas copiaria o ponteiro. Assim, a e b apontariam para o mesmo buffer, e o destrutor seria chamado duas vezes, causando double free. O construtor de cópia personalizado resolve isso alocando memória separada.

Erros comuns

  • Esquecer de alocar memória: data_ = other.data_; causa cópia superficial e double free.
  • Não copiar o terminador nulo: usar new char[strlen(other.data_)] sem +1 leva a buffer overflow.
  • Não tratar auto-atribuição: se this == &other, a cópia pode liberar a memória antes de copiar.

Outra forma de resolver

Usar std::string da biblioteca padrão, que já implementa cópia profunda corretamente:

#include <string>
std::string a = "hello";
std::string b = a;

Saída esperada

hello hello