Aproveito o curso de C++ que estou actualmente a leccionar para discutir algumas técnicas interessantes. Hoje apetece-me falar de RAII, ou seja Resource Aquisition Is Initialization, um idioma que pode fácilmente ser implementado em C++ e que pode resolver muitas dores de cabeça.
Quem vem do C já foi muitas vezes confrontado ao problema da libertação dos recursos, um exemplo clássico (em C++) será:
Esta solução é pouco elegante e potencialmente perigosa: o utilizador de f() pode esquecer-se de libertar a memória gerando uma fuga de memória (memory leak).
A solução do problema passa pela utilização de uma classe que assegure a libertação automática da memória, ou seja o pointer passará a ser gerido por um objecto que libertará a memória no destructor, como este é chamado automáticamente deixa de ser necessário chamar manualmente o delete. Usando a livraria standard isto daria:
Neste exemplo o destructor de auto_ptr é executado automáticamente no fim de my_func o que provoca a libertação da memória sem nenhuma intervenção do programador.
Quem vem do C já foi muitas vezes confrontado ao problema da libertação dos recursos, um exemplo clássico (em C++) será:
void my_func()
{
...
char *my_val=f();
...
delete my_val;
}
char *f()
{
...
char * res=new char;
return res;
}
Esta solução é pouco elegante e potencialmente perigosa: o utilizador de f() pode esquecer-se de libertar a memória gerando uma fuga de memória (memory leak).
A solução do problema passa pela utilização de uma classe que assegure a libertação automática da memória, ou seja o pointer passará a ser gerido por um objecto que libertará a memória no destructor, como este é chamado automáticamente deixa de ser necessário chamar manualmente o delete. Usando a livraria standard isto daria:
void my_func()
{
...
std::auto_ptr<char>my_val=f();
...
}
auto_ptr<char>f()
{
...
std::auto_ptr<char> res(new char);
return res;
}
Neste exemplo o destructor de auto_ptr é executado automáticamente no fim de my_func o que provoca a libertação da memória sem nenhuma intervenção do programador.
Mas isto faz com que as minhas funções devolvam todas auto_ptr(s).
ResponderEliminarIsto não torna o código mais dificil de ler ?.
Deixa lá pensar... O destrutor do my_val é executado porque a variável sai de scope.
Se usar auto_ptr como variáveis da classe fica ainda mais dificil de ler o programa pois o tipo de todas elas é auto_ptr.
O auto_ptr é uma classe que tem um construtor que recebe um void * e que tem um destrutor que liberta o espaço apontado pelo que recebeu no construtor?
De qualquer forma, neste caso também não é preciso destruir nada porque o destrutor de auto_ptr é executado quando é feito o delete ao objecto.
Esclarecimentos avulsos:
ResponderEliminar1) Só as funções que devolvem apontadores de memória dinamica devem devolver algum tipo de "smart pointer" de que o std::auto_ptr é um exemplo. Óbviamente que as funções podem continuar a devolver por valor, ou por referência.
2) std::auto_ptr<T> é um template, o constructor recebe um T * e não um void * aliás essa é uma das vantagens de usar "smart pointers" pois aumenta a "type safety".
3) A utilização de typedefs pode aumentar muito a lisibilidade do código se os std::auto_ptr<T> te dão urticária.
Corrigi o post pois o blog tinha apagado os argumentos de template.
ResponderEliminar