Separar un puntero desde un shared_ptr? [duplicar]
-
11-09-2019 - |
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í?
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)