auto_ptr e tratamento de exceções: Parte I

O que é o auto_ptr?

O auto_ptr é um template da biblioteca padrão que usa o design “smart pointer” de recuperação de memória alocada quando o “auto_ptr” sai do escopo, portanto, sendo usado para criar um código seguro em caso de exceções(exception-safe).

Quando você usa um “auto_ptr“, a diferenciação( ato de referenciar o que um ponteiro aponta, *p ), é idêntica a de um ponteiro normal.

O que muda?

  • Limpeza automática.
  • Semântica de proprietário único:
  • 2 auto_ptr não devem apontar para o mesmo recurso.
  • Na atribuição ou em uso em construtores de copia, o auto_ptr de origem passa a propriedade para o auto_ptr de destino e é zerado .
  • Construtor default zera o auto_ptr.

Declaração do auto_ptr

#include <memory>

template<class X> class auto_ptr {
		template<class y> struct auto_ptr_ref{ ... };
		X *p;
	public:
		explict auto_ptr( X* pp ) throw() { p=pp; }
		~auto_ptr(){ delete p; }
		auto_ptr( auto_ptr &a ) throw() { p=a.p ; a.p=0 ; }
		auto_ptr& operator=( auto_ptr &a ){ p=a.p ; a.p=0 ; }
		....
		X& operator*(){ return *p; }
		X* operator->(){ return p; }
		X* get(){ return p; }
		X* release(){ X* t=p ; p=0 ; return t; }
		void reset( X* pp=0 );
};

Exemplo de Erro

void f(circulo *pc){
	auto_ptr<Circulo> p2=pc; // p2 recebe propriedade de pc
	auto_ptr<Circulo> p3=p2; // p3 recebe propriedade de p2
	p2->m=7; // ERRO!!!!
	Forma *ps = p3.get(); // ps -> pc
	auto_ptr<Forma> aps = p3 ; // aps recebe propriedade, p3 recebe NULL.
	auto_ptr<Circulo> p4 = pc ; // p4 recebe propriedade de pc
}
  • aps: Destrói o objeto circulo passado via *pc
  • p4: Da um duplo delete. Isso gera um erro que depende do sistema operacional.
  • pc: dangling(vai perder a referencia a um recurso valido)

Erros em containers

A semântica de copia destrutiva do auto_ptr torna ele inadequado para ser usado em containers ou algoritmos da biblioteca padrão, como sort() ou vector:

vector<auto_ptr<Forma> > v;
. . .
sort(v.begin(), v.end());

Quando v.begin() e v.end() forem passados por copia para sort() ou em algum momento ele for copiado dentro de sort(), o auto_ptr dentro do vector sera invalidado dando a sua propiedade para quem recebeu a copia. Isso pode ocasionar um erro e normalmente não é o comportamento que você espera para um vector.

Técnicas para usar auto_ptr e deixar o código seguro

Normalmente, auto_ptr é usado para deixar o código segura ao disparo de exceções(exception-safe) de forma elegante. Ou seja, para evitar todos os problemas com exceções que a gente viu anteriormente, sem precisar escrever mais código para isso ou prejudicar a legibilidade do seu código.

Para isso, se tem algumas técnicas:

Transferência de propriedade:

Consiste em adquirir o recurso para o auto_ptr e deixar sobre sua responsabilidade ate que você entregue ao dono final do recurso, que devera ter a responsabilidade por ele. Depois, é só liberar o auto_ptr da responsabilidade do recurso.

exemplo:

void add_new( vector <T*> &v ){
	auto_ptr<T> ap( new T() );
	v.push_back( ap.get() );
	ap.release();
}

Commit:

Técnica conhecida em banco de dados, consiste em fazer as operações e só depois atualizar de forma permanente os dados em um único trecho, quando tudo já estiver seguro.

Deve se tomar cuidado quando houver copias do objeto, nesses casos você deve fazer um construtor de copia.

exemplo:

class X{
	private:
		T *p1, *p2;
	public:
		X(){
			auto_ptr ap1( new T() );
			auto_ptr ap2( new T() );
			p1 = ap1.release() ;
			p2 = ap2.release() ;
		}
		~X(){
			delete p1;
			delete p2;
		}
};

Usando auto_ptr em classes:

Esse ultimo é uma forma mais elegante de se fazer se você estiver usando uma classe. Você só instância o auto_ptr no escopo da classe e o usa na classe.

Deve se tomar cuidado quando houver copias do objeto, nesses casos você deve fazer um construtor de copia.

Exemplo:

class X{
	private:
		auto_ptr<T> p1, p2;
	public:
		X() : 	p1( new T() ),
			p2( new T() )
		{ }
};
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: