2009-12-02 7 views
21

Duplicar posible:
How to release pointer from boost::shared_ptr?Separar un puntero de un shared_ptr?

Una función de mi interfaz devuelve un puntero a un objeto. Se supone que el usuario se apropia de ese objeto. No quiero devolver un Boost.shared_ptr, porque no quiero obligar a los clientes a usar boost. Internamente, sin embargo, me gustaría almacenar el puntero en un shared_ptr para evitar fugas de memoria en caso de excepciones, etc. Parece que no hay forma de separar un puntero de un puntero compartido. Alguna idea aqui?

+0

¿Es una opción devolver una copia del objeto compartido y dejar que el puntero inteligente limpie el original? – TimW

+0

No realmente, el objeto es un videoframe en resolución HD, por lo que copiar es costoso. –

+0

Tenga en cuenta que C++ 11 tiene std :: unique_ptr que se puede usar para almacenar temporalmente el puntero y soltarlo a su regreso. – Adversus

Respuesta

23

Lo que estás buscando es una función release; shared_ptr no tiene una función de liberación. Per the Boost manual:

P. ¿Por qué shared_ptr no proporciona una función de liberación()?

A. shared_ptr no puede revelar la propiedad a menos que sea unique() porque la otra copia seguirá destruyendo el objeto.

considerar:

shared_ptr<int> a(new int); 
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2 

int * p = a.release(); 

// Who owns p now? b will still call delete on it in its destructor. 

Por otra parte, el puntero devuelto por la liberación() sería difícil de anular la planificación fiable, ya que la fuente de shared_ptr pudo haber sido creado con un Deleter personalizado.

dos opciones que podría considerar:

  • usted podría utilizar std::tr1::shared_ptr, lo que requeriría a los usuarios a utilizar una aplicación C++ biblioteca de apoyo TR1 o a usar Boost; al menos esto les daría la opción entre los dos.
  • Puede implementar su propio puntero compartido similar a boost::shared_ptr y usarlo en sus interfaces externas.

También puede consultar la discusión en esta pregunta sobre using boost::shared_ptr in a library's public interface.

+0

Ok, temí que podría ser algo así. –

+5

shared_ptr es un poco como la palabra clave const, agréguela en un solo lugar y debe usarla en todas partes –

+0

Lectores: Desplácese hacia abajo: [Haga su propio eliminador] (http://stackoverflow.com/a/5995770/321013) –

2

Como James está bien cubierto, no se puede separar un puntero compartido.

¿Necesita varios propietarios internamente o está transfiriendo la propiedad de su clase al cliente? En ese caso, un std::auto_ptr podría encajar en la factura.

Si usted está preocupado acerca de los sorprendentes semántica de std::auto_ptr, se podría sostener que internamente por boost::scoped_ptr, y separar en el punto de entregarlo a cabo - dejando al cliente para eliminar manualmente o almacenarlo en su poseer un puntero inteligente.

Si tiene varios propietarios de su lado, puede usar un conteo intrusivo. Internamente, podría usar boost::intrusive__ptr, pero entregue el puntero sin formato en la interfaz.El cliente puede trabajar de forma manual con un recuento árbitro, o almacenarlo en un boost::intrusive_ptr sí mismos (pero no hacerlos dependen de él)

11

El usuario se supone que debe tomar posesión de ese objeto. No quiero volver a un Boost.shared_ptr,

shared_ptr expresa compartían la propiedad, y quiere que su interfaz para expresar transferencia de propiedad. std::auto_ptr sería, por lo tanto, más aplicable aquí.

Internamente sin embargo, me gustaría para almacenar el puntero en un shared_ptr para evitar pérdidas de memoria en caso de excepciones

Una vez más, shared_ptr puede no ser la mejor herramienta para ese trabajo. Para evitar fugas en el caso de excepciones, sería mejor usar scoped_ptr o auto_ptr.

22

siempre hay una manera :-)

En efecto, existe una razón por la que no proporcionan un método de desbloqueo(), pero no es imposible crear una. Crea tu propio eliminador. Algo en la línea de (en realidad no han compilado el código, pero esta es la idea general):

template <typename T> 
class release_deleter{ 
public: 
    release_deleter() : released_(new some_atomic_bool(false)){} 
    void release() {released_->set(true);} 
    void operator()(T* ptr){if(!released_->get()) delete ptr;} 
private: 
    shared_ptr<some_atomic_bool> released_; 
} 

.. 

shared_ptr<some_type> ptr(new some_type, release_deleter<some_type>()); 

.. 

release_deleter<some_type>* deleter = get_deleter<release_deleter<some_type>>(ptr); 
deleter->release(); 
some_type* released_ptr = ptr.get(); 
+0

¿Por qué? es el miembro privado 'released_' un shared_ptr? –

+1

Me preguntaba lo mismo. Lo hice como un bool normal y se adaptaba perfectamente a mis necesidades. – David

+0

Sin motivo. En realidad, no había investigado el código, pero ahora veo que el eliminador se almacena con el shared_count, por lo que no se necesitaría compartir más. – Magnus

4

Utilice un shared_ptr a un scoped_ptr al recurso (shared_ptr<scoped_ptr<Resource>>). De esta forma obtendrás el recuento de referencias de shared_ptr, que destruirá automáticamente el recurso si y solo si aún está conectado al scoped_ptr. Pero puede desconectar el scoped_ptr cuando esté listo para transferir la propiedad.

+0

Inteligente, pero ahora tienes que cambiar * p a ** p en todos lados. Esto muestra un problema con el diseño 'shared_ptr'. – curiousguy

+2

@curiousguy: ¿Con qué frecuencia usas '*' en un puntero inteligente? Usualmente usas '->', que tiene semántica de encadenamiento. Y de todos modos, la misma sintaxis exacta no era necesaria en la pregunta, y esto tiene la ventaja de funcionar exactamente como el OP deseado. –

+1

"_ ¿Con qué frecuencia usa * en un puntero inteligente?_ "No sé". _ Usualmente usas ->, que tiene semántica de encadenamiento._ "Inteligente, olvidé eso. Pero no me gusta el doble indirecto: ya que la falta de 'lanzamiento' es solo una deficiencia de 'shared_ptr' diseño, así que no me gustaría cambiar el código que lo usa solo por este motivo. Prefiero trabajar en torno a la limitación arbitraria cambiando el eliminador: eso es un indirecto adicional también, pero no afecta el código que usa el puntero inteligente. (Pero en realidad prefiero escribir mi propio puntero inteligente sin las limitaciones 'shared_ptr'.) – curiousguy

Cuestiones relacionadas