¿Separar un puntero de un RPP compartido? [duplicar]


Posible Duplicado:
Cómo liberar puntero de boost:: shared_ptr?

Una función de mi interfaz devuelve un puntero a un objeto. Se supone que el usuario debe tomar posesión de ese objeto. No quiero devolver un impulso.shared_ptr, porque no quiero forzar 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 manera de separar un puntero desde un puntero compartido. ¿Alguna idea?

Author: Community, 2009-12-02

5 answers

Lo que estás buscando es una función release; shared_ptr no tiene una función release. Según el manual de Boost :

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

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

Considere:

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 release() sería difícil de desasignar de forma fiable, ya que la fuente shared_ptr podría haber sido creado con un deleter personalizado.

Dos opciones que podrías considerar:

  • Podría usar std::tr1::shared_ptr, lo que requeriría que sus usuarios usen una implementación de biblioteca de C++ compatible con TR1 o para 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 mirar la discusión en esta pregunta acerca de usando boost::shared_ptr en la interfaz pública de una biblioteca.

 25
Author: James McNellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:30:49

Siempre hay una manera: -)

Hay una razón por la que no proporcionan un método release (), pero no es imposible crear uno. Haz tu propio deleter. Algo en la línea de (en realidad no han compilado el código, pero esta es la noción 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();
 23
Author: Magnus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-13 17:45:40

Se supone que el usuario debe tomar posesión de ese objeto. No quiero devolver un impulso.shared_ptr,

shared_ptr expresa propiedad compartida, y desea que su interfaz exprese transferencia de propiedad. std::auto_ptr sería así más aplicable aquí.

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

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

 11
Author: Éric Malenfant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-02 15:07:06

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

 4
Author: Ben Voigt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-29 22:40:13

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 al cliente? En ese caso, un std::auto_ptr podría encajar en la factura.

Si le preocupa la sorprendente semántica de std::auto_ptr, podría sostenerlo internamente por boost::scoped_ptr y separarlo en el punto en que lo entregue, dejando que el cliente lo elimine manualmente o lo almacene en su propio puntero inteligente.

Si lo haces tenga varios propietarios de su lado, podría usar un conteo intrusivo. Internamente podría usar boost::intrusive__ptr, pero entregar el puntero raw en la interfaz. El cliente puede entonces trabajar manualmente con recuentos de ref, o almacenarlo en un boost::intrusive_ptr ellos mismos (pero usted no hace que dependan de él)

 2
Author: philsquared,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-02 15:06:39