c++ boost shared-ptr

c++ - ¿Cómo liberar el puntero de boost:: shared_ptr?



shared-ptr (14)

Aquí hay un truco que podría funcionar. No lo recomendaría a menos que estés en un aprieto real.

template<typename T> T * release_shared(std::shared_ptr<T> & shared) { static std::vector<std::shared_ptr<T> > graveyard; graveyard.push_back(shared); shared.reset(); return graveyard.back().get(); }

¿Puede impulsar :: shared_ptr liberar el puntero almacenado sin eliminarlo?

Puedo ver que no existe una función de liberación en la documentación, también en las preguntas frecuentes se explica por qué no proporciona la función de liberación, algo así como que la versión no se puede hacer en punteros que no son únicos. Mis punteros son únicos. ¿Cómo puedo lanzar mis punteros? ¿O que potenciar la clase de puntero inteligente para usar eso me permitirá liberar el puntero? Espero que no digas usar auto_ptr :)


Estoy utilizando Poco :: HTTPRequestHandlerFactory que espera devolver un HTTPRequestHandler * sin formato, el marco Poco borra el controlador una vez que finaliza la solicitud.

También usando el proyecto DI Sauce para crear los controladores, sin embargo, el inyector devuelve shared_ptr que no puedo devolver directamente, y regresar handler.get () tampoco sirve, ya que tan pronto como esta función retorna, shared_ptr sale del alcance y elimina el controlador. antes de su ejecución, así que aquí hay una razón razonable (creo) para tener un método .release (). Terminé creando una clase HTTPRequestHandlerWrapper de la siguiente manera:

class HTTPRequestHandlerWrapper : public HTTPRequestHandler { private: sauce::shared_ptr<HTTPRequestHandler> _handler; public: HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) { _handler = handler; } virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) { return _handler->handleRequest(request, response); } };

y luego la fábrica

HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) { URI uri = URI(request.getURI()); auto path = uri.getPath(); auto method = request.getMethod(); sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path); return new HTTPRequestHandlerWrapper(handler); }

que satisfizo tanto a Sauce como a Poco y funciona muy bien.


La base de compartir es la confianza. Si alguna instancia en su programa necesita liberar el puntero sin formato, es casi seguro que shared_ptr es del tipo incorrecto.

Sin embargo, recientemente también quise hacer esto, ya que necesitaba desasignar desde un proceso diferente. Al final me enseñaron que mi decisión anterior de usar std::shared_ptr no fue pensada.

Acabo de usar rutinariamente este tipo para la limpieza. Pero el puntero solo se duplicó en algunos lugares. En realidad, necesitaba un std::unique_ptr , que (sorpresa) tiene una función de release .


Necesita utilizar un eliminador de diapositivas que puede solicitar para no eliminar el puntero subyacente.

Vea esta respuesta (que ha sido marcada como un duplicado de esta pregunta) para más información.


Necesitaba pasar un puntero a través de controladores asíncronos y mantener el comportamiento de autodestrucción en caso de error, pero la API final esperaba un puntero sin formato, por lo que hice que esta función se liberara desde un solo shared_ptr:

#include <memory> template<typename T> T * release(std::shared_ptr<T> & ptr) { struct { void operator()(T *) {} } NoDelete; T * t = nullptr; if (ptr.use_count() == 1) { t = ptr.get(); ptr.template reset<T>(nullptr, NoDelete); } return t; }

Si ptr.use_count() != 1 obtendrá un nullptr lugar.


Niños, no hagas esto en casa:

// set smarty to point to nothing // returns old(smarty.get()) // caller is responsible for the returned pointer (careful) template <typename T> T* release (shared_ptr<T>& smarty) { // sanity check: assert (smarty.unique()); // only one owner (please don''t play games with weak_ptr in another thread) // would want to check the total count (shared+weak) here // save the pointer: T *raw = &*smarty; // at this point smarty owns raw, can''t return it try { // an exception here would be quite unpleasant // now smash smarty: new (&smarty) shared_ptr<T> (); // REALLY: don''t do it! // the behaviour is not defined! // in practice: at least a memory leak! } catch (...) { // there is no shared_ptr<T> in smarty zombie now // can''t fix it at this point: // the only fix would be to retry, and it would probably throw again // sorry, can''t do anything abort (); } // smarty is a fresh shared_ptr<T> that doesn''t own raw // at this point, nobody owns raw, can return it return raw; }

Ahora, ¿hay alguna manera de verificar si el conteo total de propietarios para el recuento de ref es> 1?


No estoy del todo seguro si su pregunta es sobre cómo lograr esto, pero si desea comportamiento desde un shared_ptr , donde, si libera el valor de un shared_ptr , todos los demás punteros compartidos con el mismo valor se convierten en un nullptr, entonces puede pon un unique_ptr en un shared_ptr para lograr ese comportamiento.

void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr) { if(ptr == nullptr || *ptr == nullptr) { std::cout << name << " points to nullptr" << std::endl; } else { std::cout << name << " points to value " << *(*ptr) << std::endl; } } int main() { std::shared_ptr<std::unique_ptr<int>> original; original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50)); std::shared_ptr<std::unique_ptr<int>> shared_original = original; std::shared_ptr<std::unique_ptr<int>> thief = nullptr; print(std::string("original"), original); print(std::string("shared_original"), shared_original); print(std::string("thief"), thief); thief = std::make_shared<std::unique_ptr<int>>(original->release()); print(std::string("original"), original); print(std::string("shared_original"), shared_original); print(std::string("thief"), thief); return 0; }

Salida:

original points to value 50 shared_original points to value 50 thief points to nullptr original points to nullptr shared_original points to nullptr thief points to value 50

Este comportamiento le permite compartir un recurso (como una matriz) y luego reutilizar ese recurso al tiempo que invalida todas las referencias compartidas a este recurso.


No lo hagas Entrada de preguntas frecuentes de Boost:

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

A shared_ptr no puede revelar la propiedad a menos que sea único () 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.

Además, el puntero devuelto por la versión () sería difícil de desasignar confiablemente, ya que la fuente shared_ptr podría haberse creado con un eliminador personalizado.

Por lo tanto, esto sería seguro en caso de que sea la única instancia shared_ptr que apunte a su objeto (cuando unique () devuelva verdadero) y el objeto no requiera un eliminador especial. Todavía cuestionaría tu diseño, si usaste una función .release ().


Para que el puntero señale nada nuevamente, puede llamar a shared_ptr::reset() .

Sin embargo, esto eliminará el objeto al que apunta cuando su puntero es la última referencia al objeto. Esto, sin embargo, es exactamente el comportamiento deseado del puntero inteligente en primer lugar.

Si solo desea una referencia que no mantenga el objeto vivo, puede crear un boost::weak_ptr (consulte la documentación de refuerzo ). Un weak_ptr contiene una referencia al objeto, pero no lo agrega al recuento de referencia, por lo que el objeto se elimina cuando solo existen referencias débiles.


Perdónalos porque no saben lo que hacen. Este ejemplo funciona con boost :: shared_ptr y msvs std :: shared_ptr sin pérdidas de memoria.

template <template <typename> class TSharedPtr, typename Type> Type * release_shared(TSharedPtr<Type> & ptr) { //! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr ) struct SharedVoidPtr { struct RefCounter { long _Uses; long _Weaks; }; void * ptr; RefCounter * refC; SharedVoidPtr() { ptr = refC = nullptr; } ~SharedVoidPtr() { delete refC; } }; assert( ptr.unique() ); Type * t = ptr.get(); SharedVoidPtr sp; // create dummy shared_ptr TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp ); spPtr->swap(ptr); // swap the contents ptr.reset(); // now the xxx::shared_ptr is empy and // SharedVoidPtr releases the raw poiter but deletes the underlying counter data return t; }


Podría usar el eliminador falso. Entonces, los punteros no se eliminarán en realidad.

struct NullDeleter {template<typename T> void operator()(T*) {} }; // pp of type some_t defined somewhere boost::shared_ptr<some_t> x(pp, NullDeleter() );


Puede eliminar el puntero compartido, que me parece mucho igual. Si los punteros son siempre únicos, entonces std::auto_ptr<> es una buena opción. Tenga en cuenta que los punteros únicos no se pueden usar en contenedores STL, ya que las operaciones en ellos hacen una gran cantidad de copias y duplicaciones temporales.


Si los punteros son realmente únicos, utilice std::unique_ptr o boost::scoped_ptr si el primero no está disponible para su compilador. De lo contrario, considere combinar el uso de boost::shared_ptr con boost::weak_ptr . Consulte la documentación de Boost para más detalles.


Solución fácil, aumente la referencia y luego filtre el shared_pointer.

boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType()); new boost::shared_ptr<MyType>(); MyType * raw_pointer = shared_pointer_to_instance.get()

Esto causará claramente una pérdida de memoria de shared_ptr y MyType *