Médio C++
Gerenciador de buffer RAII
Enunciado
Implemente uma classe Buffer que aloca um array de int no construtor e o libera no destrutor. A classe deve ter um método set(int index, int value) e get(int index). No main, crie um Buffer de tamanho 5, preencha com valores e imprima. Em seguida, force uma exceção para verificar que a memória é liberada.
Requisitos
- Alocar memória dinamicamente no construtor com
new int[tamanho]. - Liberar no destrutor com
delete[]. - Desabilitar cópia para evitar dupla liberação.
- Métodos
setegetcom verificação de limites (lançarstd::out_of_range).
Código inicial
#include <iostream>
#include <stdexcept>
class Buffer {
int* dados_;
size_t tamanho_;
public:
// TODO: construtor, destrutor, set, get
};
int main() {
// TODO: testar
return 0;
}
Saída esperada
Buffer de 5 elementos criado
0 10 20 30 40
Excecao capturada: indice fora dos limites
Buffer destruido
Ver dica
No destrutor, use delete[] dados_;. Para desabilitar cópia, declare Buffer(const Buffer&) = delete; e Buffer& operator=(const Buffer&) = delete;.
Mostrar solução
#include <iostream>
#include <stdexcept>
class Buffer {
int* dados_;
size_t tamanho_;
public:
Buffer(size_t tamanho) : tamanho_(tamanho) {
dados_ = new int[tamanho];
std::cout << "Buffer de " << tamanho << " elementos criado\n";
}
~Buffer() {
delete[] dados_;
std::cout << "Buffer destruido\n";
}
// Desabilita cópia
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
void set(size_t index, int value) {
if (index >= tamanho_) {
throw std::out_of_range("indice fora dos limites");
}
dados_[index] = value;
}
int get(size_t index) const {
if (index >= tamanho_) {
throw std::out_of_range("indice fora dos limites");
}
return dados_[index];
}
size_t tamanho() const { return tamanho_; }
};
int main() {
try {
Buffer buf(5);
for (size_t i = 0; i < buf.tamanho(); ++i) {
buf.set(i, static_cast<int>(i * 10));
}
for (size_t i = 0; i < buf.tamanho(); ++i) {
std::cout << buf.get(i) << ' ';
}
std::cout << '\n';
// Força exceção: acesso fora dos limites
buf.set(10, 99);
} catch (const std::exception& e) {
std::cerr << "Excecao capturada: " << e.what() << '\n';
}
return 0;
}
Passo a passo
- A classe
Buffertem um ponteiroint* dados_e umsize_t tamanho_. - O construtor aloca um array de
intcomnew int[tamanho]e imprime uma mensagem. - O destrutor libera a memória com
delete[] dados_e imprime uma mensagem. - Desabilitamos a cópia com
= deletepara evitar que dois objetos apontem para o mesmo array (o que causaria dupla liberação). - Os métodos
setegetverificam se o índice está dentro dos limites; se não, lançamstd::out_of_range. - No
main, criamos umBufferde tamanho 5 dentro de um blocotry. - Preenchemos e imprimimos os valores.
- Forçamos uma exceção chamando
set(10, 99), que está fora dos limites. - A exceção é capturada; o destrutor do
Bufferé chamado automaticamente durante o stack unwinding, liberando a memória.
Por que funciona
O destrutor é invocado mesmo quando uma exceção é lançada, desde que o objeto tenha sido completamente construído. Assim, a memória alocada é liberada sem vazamentos. A desabilitação da cópia evita que múltiplos objetos gerenciem o mesmo recurso, o que levaria a double free.
Erros comuns
- Esquecer
delete[]: vazamento de memória. Usedelete[]para arrays. - Permitir cópia: se você copiar o
Buffer, ambos os objetos terão o mesmo ponteiro e o destrutor de cada um tentará liberar a mesma memória, causando double free. Solução: desabilitar cópia ou implementar construtor de cópia profunda. - Não verificar limites: acessar fora do array é comportamento indefinido. Sempre valide índices.
- Lançar exceção no construtor após alocar: se o construtor lançar depois de
new, o destrutor não será chamado e a memória vazará. Neste exemplo, não lançamos após alocar, mas em casos reais usestd::unique_ptrpara evitar isso.
Outra forma de resolver
Usar std::vector<int> em vez de gerenciar memória manualmente. O std::vector já implementa RAII e cuida de tudo.
Saída esperada
Buffer de 5 elementos criado
0 10 20 30 40
Excecao capturada: indice fora dos limites
Buffer destruido