Desafio C++

Gerenciamento de recurso com construtor e destrutor

Enunciado

Implemente uma classe Buffer que gerencia um array dinâmico de inteiros. Ela deve:

  • Ter um construtor padrão que cria um buffer vazio (tamanho 0).
  • Ter um construtor explicit que recebe um tamanho e aloca memória dinamicamente.
  • Ter um destrutor que libera a memória alocada.
  • Ter um método set(int indice, int valor) que define um valor em uma posição.
  • Ter um método get(int indice) const que retorna o valor em uma posição.
  • Ter um método tamanho() const que retorna o tamanho do buffer.

No main, crie um Buffer com tamanho 5, preencha com valores de 0 a 4, mostre os valores e o tamanho. Depois crie um Buffer padrão e mostre seu tamanho.

Requisitos

  • O construtor com tamanho deve alocar memória com new int[tamanho].
  • O destrutor deve liberar a memória com delete[].
  • Os métodos set e get devem acessar posições válidas (assuma que o índice é válido).
  • O programa deve exibir Buffer: 0 1 2 3 4 e Tamanho: 5 e Buffer padrao tamanho: 0.

Código inicial

#include <iostream>

class Buffer {
public:
    // TODO: construtor padrão
    // TODO: construtor explicit com tamanho
    // TODO: destrutor
    void set(int indice, int valor) { /* TODO */ }
    int get(int indice) const { /* TODO */ }
    int tamanho() const { /* TODO */ }
private:
    int* dados_;
    int tamanho_;
};

int main() {
    // TODO: criar Buffer(5), preencher e mostrar
    // TODO: criar Buffer padrão e mostrar tamanho
    return 0;
}

Saída esperada

Buffer: 0 1 2 3 4
Tamanho: 5
Buffer padrao tamanho: 0
Ver dica

No construtor padrão, inicialize dados_ como nullptr e tamanho_ como 0. No construtor com tamanho, aloque com new int[tamanho] e inicialize os elementos se necessário. No destrutor, use delete[] dados_.

Mostrar solução
#include <iostream>

class Buffer {
public:
    // Construtor padrão: buffer vazio
    Buffer() : dados_(nullptr), tamanho_(0) {}

    // Construtor explícito: aloca array de inteiros
    explicit Buffer(int tamanho) : dados_(new int[tamanho]), tamanho_(tamanho) {
        // Inicializa com zeros (opcional)
        for (int i = 0; i < tamanho_; ++i) {
            dados_[i] = 0;
        }
    }

    // Destrutor: libera memória
    ~Buffer() {
        delete[] dados_;
    }

    void set(int indice, int valor) {
        dados_[indice] = valor;
    }

    int get(int indice) const {
        return dados_[indice];
    }

    int tamanho() const {
        return tamanho_;
    }

private:
    int* dados_;
    int tamanho_;
};

int main() {
    Buffer buf(5);
    for (int i = 0; i < buf.tamanho(); ++i) {
        buf.set(i, i);
    }

    std::cout << "Buffer: ";
    for (int i = 0; i < buf.tamanho(); ++i) {
        std::cout << buf.get(i) << (i < buf.tamanho() - 1 ? " " : "\n");
    }
    std::cout << "Tamanho: " << buf.tamanho() << "\n";

    Buffer padrao;
    std::cout << "Buffer padrao tamanho: " << padrao.tamanho() << "\n";

    return 0;
}

Passo a passo

  1. A classe Buffer tem dois membros privados: dados_ (ponteiro para int) e tamanho_ (int).
  2. O construtor padrão inicializa dados_ como nullptr e tamanho_ como 0, representando um buffer vazio.
  3. O construtor explicit Buffer(int tamanho) aloca um array dinâmico com new int[tamanho] e inicializa todos os elementos com 0.
  4. O destrutor ~Buffer() libera a memória alocada com delete[] dados_. É crucial para evitar vazamentos de memória.
  5. O método set atribui um valor a uma posição do array.
  6. O método get retorna o valor de uma posição.
  7. tamanho() retorna o tamanho do buffer.
  8. No main, criamos Buffer buf(5), preenchemos com i e imprimimos os valores. Depois criamos Buffer padrao e mostramos seu tamanho.

Por que funciona

O construtor com tamanho aloca memória dinamicamente e o destrutor a libera, seguindo o princípio RAII (Resource Acquisition Is Initialization). O construtor padrão cria um buffer vazio sem alocar memória, e o destrutor lida com nullptr sem problemas (delete[] em nullptr é seguro). O explicit impede conversões implícitas de int para Buffer.

Erros comuns

  • Esquecer de liberar a memória no destrutor: ~Buffer() {} causa vazamento de memória.
  • Usar delete em vez de delete[] para um array alocado com new[]: delete dados_; é comportamento indefinido. Use delete[].
  • Não inicializar dados_ no construtor padrão: se não for inicializado, o destrutor pode tentar liberar memória inválida. Inicialize com nullptr.
  • Tentar copiar um Buffer sem definir construtor de cópia: a cópia padrão copia o ponteiro, levando a double free. Para este exercício, não é necessário, mas é bom saber.

Outra forma de resolver

Usar std::vector<int> em vez de ponteiro bruto, eliminando a necessidade de destrutor manual. No entanto, o objetivo aqui é praticar gerenciamento manual de recursos.

Saída esperada

Buffer: 0 1 2 3 4
Tamanho: 5
Buffer padrao tamanho: 0