Can boost::shared_ptr release the stored pointer without deleting it?
I can see no release fu开发者_运维技巧nction exists in the documentation, also in the FAQ is explained why it does not provide release function, something like that the release can not be done on pointers that are not unique. My pointers are unique. How can I release my pointers ? Or which boost smart pointer class to use that will allow me releasing of the pointer ? I hope that you won't say use auto_ptr :)
Don't. Boost's FAQ entry:
Q. Why doesn't shared_ptr provide a release() function?
A. shared_ptr cannot give away ownership unless it's unique() because the other copy will still destroy the object.
Consider:
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.
Furthermore, the pointer returned by release() would be difficult to deallocate reliably, as the source shared_ptr could have been created with a custom deleter.
So, this would be safe in case it's the only shared_ptr instance pointing to your object (when unique() returns true) and the object doesn't require a special deleter. I'd still question your design, if you used such a .release() function.
You could use fake deleter. Then pointers will not be deleted actually.
struct NullDeleter {template<typename T> void operator()(T*) {} };
// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );
Kids, don't do this at home:
// 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;
}
Now, is there a way to check if total count of owners for the ref count is > 1?
You need to use a deleter that you can request not to delete the underlying pointer.
See this answer (which has been marked as a duplicate of this question) for more information.
To let the pointer point to nothing again, you can call shared_ptr::reset()
.
However, this will delete the object pointed to when your pointer is the last reference to the object. This, however, is exactly the desired behaviour of the smart pointer in the first place.
If you just want a reference that does not hold the object alive, you can create a boost::weak_ptr
(see boost documentation). A weak_ptr
holds a reference to the object but does not add to the reference count, so the object gets deleted when only weak references exist.
The basis of sharing is trust. If some instance in your program needs to release the raw pointer, it is almost for sure that shared_ptr
is the wrong type.
However, recently I wanted to do this too, as I needed to deallocate from a different process-heap. In the end I was taught that my older decision to use some std::shared_ptr
was not thought-out.
I just routinely used this type for cleanup. But the pointer was just duplicated on a few places. Actually I needed a std::unique_ptr
, which (suprise) has a release
function.
Forgive them for they know not what they do. This example works with boost::shared_ptr and msvs std::shared_ptr without memory leaks!
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;
}
You can delete the shared pointer, which seems much the same to me. If pointers are always unique, then std::auto_ptr<>
is a good choice. Bear in mind that unique pointers can't be used in STL containers, since operations on them do a lot of copying and temporary duplication.
I'm not entirely sure if your question is about achieving this, but if you want behaviour from a shared_ptr
, where, if you release the value from one shared_ptr
, all the other shared pointers to the same value become a nullptr, then you can put a unique_ptr
in a shared_ptr
to achieve that behaviour.
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;
}
Output:
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
This behaviour allows you to share a resource (like an array), then later reuse that resource while invalidating all the shared references to this resource.
Here's a hack that might work. I wouldn't recommend it unless you're in a real bind.
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();
}
If your pointers are indeed unique do use std::unique_ptr
or boost::scoped_ptr
if the former is not available for your compiler. Otherwise consider combining the use of boost::shared_ptr
with boost::weak_ptr
. Check out the Boost documentation for details.
I am using Poco::HTTPRequestHandlerFactory which expects to return a raw HTTPRequestHandler*, the Poco framework deletes the handler once the request finishes.
Also using DI Sauce project to create the controllers, however the Injector returns shared_ptr which I cannot return directly, and returning handler.get() is no good either since the as soon as this function returns the shared_ptr goes out of scope and deletes then handler before its executed, so here is a reasonable (I think) reason to have a .release() method. I ended up creating a HTTPRequestHandlerWrapper class as follows :-
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);
}
};
and then the factory would
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);
}
which satisfied both Sauce and Poco and works nicely.
I needed to pass a pointer through async handlers and to keep the self-destruct behavior in case of failure but the final API expected a raw pointer, so I made this function to release from a single 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;
}
If ptr.use_count() != 1
you shall get a nullptr
instead.
Do note that, from cppreference (bold emphasis mine):
If
use_count
returns 1, there are no other owners. (The deprecated member functionunique()
is provided for this use case.) In multithreaded environment, this does not imply that the object is safe to modify because accesses to the managed object by former shared owners may not have completed, and because new shared owners may be introduced concurrently, such as bystd::weak_ptr::lock
.
Easy solution, increase the reference and then leak the 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()
This will clearly cause a memory leak of both the shared_ptr and the MyType *
精彩评论