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

¿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 🙂

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.

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 a(new int); shared_ptr 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 ().

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

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

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  T* release (shared_ptr& 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 (); // REALLY: don't do it! // the behaviour is not defined! // in practice: at least a memory leak! } catch (...) { // there is no shared_ptr 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 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?

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.

La base de compartir es la confianza. Si alguna instancia en su progtwig 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 .

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  

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.

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>& 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> original; original = std::make_shared>(std::make_unique(50)); std::shared_ptr> shared_original = original; std::shared_ptr> thief = nullptr; print(std::string("original"), original); print(std::string("shared_original"), shared_original); print(std::string("thief"), thief); thief = std::make_shared>(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.

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

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

Si los punteros son realmente únicos, utilice std::unique_ptr o boost::scoped_ptr si el primero no está disponible para su comstackdor. 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.

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 scope 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 _handler; public: HTTPRequestHandlerWrapper(sauce::shared_ptr 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 handler = _injector->get(method + ":" + path); return new HTTPRequestHandlerWrapper(handler); } 

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

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  template T * release(std::shared_ptr & ptr) { struct { void operator()(T *) {} } NoDelete; T * t = nullptr; if (ptr.use_count() == 1) { t = ptr.get(); ptr.template reset(nullptr, NoDelete); } return t; } 

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

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

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

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