Pregunta

  

Duplicar posible:
   Cómo liberar un puntero desde un impulso :: shared_ptr?

Una función de mi interfaz devuelve un puntero a un objeto. El usuario se supone que debe tomar posesión de ese objeto. No quiero volver a un Boost.shared_ptr, porque yo no quiero obligar a los clientes a utilizar impulso. Internamente sin embargo, me gustaría para almacenar el puntero en un shared_ptr para evitar pérdidas de memoria en caso de excepciones, etc. No parece haber ninguna manera de separar un puntero desde un puntero compartido. Cualquier idea aquí?

¿Fue útil?

Solución

Lo que estamos buscando es una función release; shared_ptr no tiene una función de liberación. según el manual de Boost :

  

Q. ¿Por qué no shared_ptr proporcionar una función de desbloqueo ()?

     

A. shared_ptr no puede ceder la propiedad a menos que sea único (), ya que la otra copia todavía va a destruir el objeto.

     

Considere lo siguiente:

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.
  

Además, 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.

Hay dos opciones que podría considerar:

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

También puede buscar en el debate en esta pregunta sobre el uso de impulso :: shared_ptr en la interfaz pública de una biblioteca .

Otros consejos

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. Haga su propio Deleter. 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();
  

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

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

  

Sin embargo Internamente, 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 las excepciones, scoped_ptr o auto_ptr serían más adecuados.

Utilice un shared_ptr a un scoped_ptr al recurso (shared_ptr<scoped_ptr<Resource>>). De esta manera se obtiene el recuento de referencias de shared_ptr, que destruirá automáticamente el recurso si y sólo si todavía está unido a la scoped_ptr. Pero se puede separar la scoped_ptr cuando esté listo para entregar fuera de la propiedad.

Como James ha cubierto bien realmente no se puede separar un puntero compartido.

¿Necesita varios propietarios internamente, o está transfiriendo la propiedad de su clase para el cliente? En ese caso, un std::auto_ptr podría caber la cuenta.

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 propio puntero inteligente.

Si usted tiene múltiples propietarios de su lado que podría utilizar un recuento intrusivo. Internamente, a continuación, podría utilizar boost::intrusive__ptr, pero la mano del puntero prima en la interfaz. El cliente puede trabajar de forma manual con un recuento árbitro, o almacenarlo en un boost::intrusive_ptr mismos (pero no hacerlos dependen de él)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top