Cita:
Iniciado por dmorill No conocía los shared_ptr ni los unique_ptr.
Son lo que se conoce como punteros inteligentes. La gracia de estas clases es que se encargan de la gestión de un puntero, destruyéndolo cuando el mismo ya no es necesario.
unique_ptr es una clase que se encarga de la gestión de un puntero que no va a ser compartido. Cuando la ejecución abandona el ámbito de la variable el puntero se destruye automáticamente:
Código C++:
Ver originalstruct Test
{
~Test()
{ std::cout << "Test::~Test()\n"; }
}
void func()
{
auto ptr = std::make_unique<Test>();
std::cout << "Despues de esto se llama al destructor\n";
}
int main()
{
func();
}
Por supuesto un unique_ptr puede sacarse de una función (e incluso almacenarse en un contenedor). La única limitación (y es su razón de ser) es que el puntero no está compartido por otros punteros inteligentes:
Código C++:
Ver originalstd::unique_ptr<Test> func()
{
return std::make_unique<Test>();
std::cout << "Aun no se llama al destructor\n";
}
int main()
{
auto ptr = func();
std::cout << "El objeto se destruye a continuacion\n";
}
Para mover el puntero de una variable a otra... por ejemplo un bucle intermedio que pretende localizar un elemento en cuestión, se debe usar la sintaxis move (recuerda que al ser un elemento único no se puede llamar al constructor copia ni al de asignación alegremente):
Código C++:
Ver originalvoid Print(std::unique_ptr<int>& var)
{
if( var )
std::cout << *var << '\n';
else
std::cout << "Puntero vacio\n";
}
int main()
{
std::unique_ptr<int> a = std::make_unique<int>(2);
std::unique_ptr<int> b;
Print(a); Print(b);
//b = a; -> ERROR de compilación
b = std::move(a); // sintaxis MOVE. a y b intercambian sus estados
Print(a); Print(b);
}
Gestionar los punteros con punteros inteligentes ayuda a reducir las fugas de memoria:
Código C++:
Ver originalstd::unique_ptr<Test> func()
{
auto obj = std::make_unique<Test>();
throw 1; // Al lanzar la excepción el objeto se destruye automáticamente
return obj;
}
int main()
{
try
{
func();
}
catch(...)
{ }
}
shared_ptr sigue la misma filosofía (proporcionar un mecanismo de gestión de la memoria) pero permite que el puntero esté compartido por varias variables. Lo que hace shared_ptr es invocar al destructor automáticamente cuando el puntero ya no tiene referencias.
El uso de shared_ptr requiere prestar atención a las referencias circulares. Recordemos que si un shared_ptr tiene al menos una referencia el objeto no se va a destruir, luego si A apunta a B y B a A, ninguno de los dos objetos se va a destruir.
Un saludo.