2010-11-16 10 views
6

Tengo un poco confundido acerca de shared_ptr.Para usar shared_ptr, ¿es seguro?

decir: Yo he clases:!

class foo { 
    int _f; 
}; 
typedef std::shared_ptr<foo> fooptr; 

class bar { 
    int _b; 
}; 
typedef std::shared_ptr<bar> barptr; 

class foobar : public foo, public bar { 
    int _fb; 
}; 

int main() { 

    foobar *fb1 = new foobar(); 
    foobar *fb2 = new foobar(); 

    fooptr f((foo *)fb1); 
    barptr b((bar *)fb2); 

    return 0; 
} 

Debido b.get() = FB2, por lo que debe bloquearse cuando la salida del programa? O es seguro?

Respuesta

10

A shared_ptr<base> puede hacerse cargo de forma segura de un derived*, incluso si base no tiene un destructor virtual.

Sin embargo, esto solo funciona si shared_ptr sabe cuál es el tipo más derivado del objeto cuando toma posesión de él. Si tuviera que eliminar los moldes

fooptr f(fb1); 
fooptr b(fb2); 

entonces definitivamente estaría bien.Con los moldes, el shared_ptr no puede saber cuál es el tipo más derivada del objeto es cuando toma posesión de ella, por lo que el comportamiento no está definido, al igual que si hubiera dicho:

foo* f = new foobar(); 
delete f; 

Lo mejor que puede hacer es seguir la regla que "a base class destructor should be either public and virtual, or protected and nonvirtual."

+0

+1, me ganaste para explicar el constructor de la plantilla. –

+0

gracias por su respuesta :) – ddh

0

foo y bar no son clases polimórficas y, por lo tanto, este código probablemente dará como resultado la desasignación del puntero no válido.

7

No, no es seguro. foo y bar necesitan destructores virtuales, de lo contrario no está definido lo que sucede cuando el destructor de shared_ptr borra el puntero que contiene. Por supuesto, decir que no es seguro no es lo mismo que decir que debería colapsar.

Como alternativa, hay un poco de magia [*] integrado en shared_ptr lo que significa que si no desechan a foo*, su código se convierte en segura:

fooptr f(fb1); 
barptr b(fb2); 

ya sea con el destructor virtual, o si usted toma los moldes, cuando shared_ptr viene a eliminar el puntero, el compilador "sabrá" cómo ajustar el puntero a su tipo original, para llamar a los destructores correctos y liberar la memoria.

La magia solo funciona porque fb1 es tipo foobar*, sin embargo. Sin el destructor virtual, lo que sigue es todavía inseguro:

foo *fb = new foobar(); 
fooptr f(fb); 

Si utiliza shared_ptr así, entonces no hay riesgo de hacer lo siguiente:

fooptr f(new foobar()); 

También puede evitar el problema de que en su código , que si la segunda llamada al new foobar() arroja una excepción, se filtra el primer objeto. Si usted va a utilizar shared_ptr a gestionar la memoria para usted, entonces usted necesita para obtener la memoria bajo la gestión lo más rápidamente posible:

fooptr f(new foobar()); 
barptr b(new foobar()); 

Ahora bien, si la segunda línea lanza, f será adecuadamente destructed y borrará el objeto.

[*] "magic" = una plantilla de constructor, que almacena en el shared_ptr un puntero a una función que devolverá el puntero almacenado al tipo correcto y luego lo eliminará.

+0

si foo y bar tienen destructor virtual, entonces es seguro? – ddh

+0

Sin embargo, elimine el rechazo explícito, y es seguro porque 'shared_ptr' tiene un constructor con plantilla que asegura la destrucción a través del tipo del puntero pasado originalmente al constructor, no el argumento de plantilla del' shared_ptr' que finalmente causa el final destrucción. Todavía es muy recomendable tener un destructor virtual en las clases base; pero no es técnicamente peligroso. –

+0

Creo que en el destructor de shared_ptr, debe haber "delete ptr", y la operación de delete do: 1) llama al desturctor del objeto, y 2) libera la memoria. Pero si la memoria recubierta es 0x10000, pero lo que el shared_ptr obtiene es 0x10004, ¿habrá algún problema? – ddh

-1

No es seguro ya que está utilizando un molde C-Style en un código C++.

NO utilice elenco C-Style, el uso arroja como static_cast, dynamic_cast, const_cast o reinterpret_cast. Además, ningún accidente no significa seguridad.

De hecho, solo retire los moldes en este caso.

+0

'dynamic_cast' se deletrea' dynamic_cast', period. – curiousguy

Cuestiones relacionadas