I need to write my own destructor for a shared pointer instance. Unfortunately, such instance is acquired from a library function call and it's not I that initialize it. So how can I "set" the destructor here?
Ideally, the code in my mind may look like
pointer.setDeleter(myDeleter);
or
pointer = std::make_shared<MyType>(pointerOld.get(), myDeleter);
I didn't find the API for the first assumption. For the second one, it is said that MyType doesn't have a constructor with 2 parameters. It is not compilable.
Any ideas for this?
Thanks!
This is the closest I can get.
template<class T>
std::shared_ptr<T> extra_deleter( std::shared_ptr<T> in, std::function<void(T*)> action ) {
if (!in) return {};
if (!action) return std::move(in);
// action=std::move(action) in c++14
auto new_deleter = [action](std::shared_ptr<T>* tin) {
action(tin->get());
delete tin;
};
auto tmp = std::shared_ptr<std::shared_ptr<T>>(
new shared_ptr<T>(std::move(in)),
std::move(new_deleter)
);
if (!tmp) return {};
// aliasing ctor:
return {tmp, tmp.get()->get()};
}
this create a shared pointer shared pointer, augments it with a custom deleter action, then uses the aliasing ctor to create a shared pointer to T.
This does not cause extra code to run when the source shared_ptr is destroyed. Instead it creates a new shared_ptr with extra destruction code in it. When the new lineage of shared_ptr dies, the action is run.
If there are no other references to the original shared_ptr state remaining, then the original destroyer of the shared_ptr runs.
Related
Currently I'm using some functions from the glib library. With glib also comes the gio. glib is a C library and therefore I need to delete some structures that I create.
for many of the objects I create a smartpointer eg:
std::shared_ptr<GAsyncQueue> my_queue = std::shared_ptr<GAsyncQueue>(g_async_queue_create(), g_async_queue_unref);
For this creates a shared pointer to an GAsyncQueue and this is safely destroys the queue on its end of its life.
However, I encounter a problem when I obtain a pointer from the gio library that I should not free. In the following code my_connection is a GSocketClient which implements (in glib speak) GIOStream.
std::shared_ptr<GInputStream> my_input_stream =
std::shared_ptr<GInputStream> (
g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()))
);
Because the documentation on GIOStream mentions, that the pointer obtained with g_io_stream_get_input_stream() should not be freed. That is because it is owned by the my_connection instance.
I thought about creating a lamda for the destroy object, the second parameter of a shared pointer object. eg auto deleter = [](GInputStream* ptr) {}; and then give that lambda as destroy function to the shared pointer, but that feels a kind of stupid.
Well, alternative to no-op deleter might be using aliasing shared pointer
template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
It shares x, but after get() you'll get back p.
Discussion: What is shared_ptr's aliasing constructor for?
You probably just don't need a std::shared_ptr. And you probably don't even need a pointer.
As I read your question and comments, I don't see any point against
auto& my_input_stream = *( g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get())) )
It is true that pointers allow optional data. However, it's also true that it's mostly used the wrong way. Having
void foo( type* ptr)
{
if (!ptr)
throw exception;
}
often doesn't make sense. If the function has to to work on concrete data, allowing a NULL parameter is only useful if you then worry about providing that data. Otherwise, just require a reference (possibly const) to the object.
Smart pointers are useful; but they're still pointers. Avoiding them altogether, if possible, is even better.
From the comments:
However, a reference must always be initialized
Absolutely. Since C++11 though we've got std::reference_wrapper which can also be reassinged and stored in containers.
You can use a deleter type that does nothing, but it will need to be passed as an argument to the shared_ptr's constructor
struct DoNothing {
template <typename T>
void operator()(T*) const noexcept { }
};
When creating a shared_ptr you will need to create one of these deleters and pass it in the constructor (as you're doing with the lambda). You can make this easier on yourself with an intermediate function
template <typename T>
std::shared_ptr<T> non_deleting_shared_ptr(T* ptr) {
return {ptr, DoNothing};
}
auto my_input_stream =
non_deleting_shared_ptr(
g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()));
However the bigger question is why you're using smart pointers when you don't want ownership to be a part of it. You'd almost certainly be better off with just a GAsyncQueue*, unless of course you're in a situation where you have a shared_ptr that needs to free sometimes. Like a data member maybe?
I have a shared pointer with a custom deleter and want to create another shared pointer from it with a custom deleter that does some work before invoking the original custom deleter. Something like...
std::shared_ptr<X> foo;
{
std::shared_ptr<X> bar(new X(), Deleter);
foo.reset(bar, My_Deleter(bar.get_deleter()));
}
When bar goes out of scope, nothing should happen because of foo. When foo goes out of scope, My_Deleter runs and then invokes Deleter.
Is it possible to chain custom deleters like this? My_Deleter stores a copy of Deleter on construction, but I'm not sure what the type declaration would look like.
You have to specify the deleter type when calling shared_ptr::get_deleter(), so you have to specialize your custom delete class accordingly.
And I'm not sure you can pass a shared_ptr object to reset() anyway. It expects a new T* pointer as input, and shared_ptr is not implicitly convertible to T*, AFAIK. Only the constructor, operator=(), and swap() method allow a shared_ptr as input to invoke sharing. The reset() documentation even warns about this:
If the object pointed to by ptr is already owned, the function results in undefined behavior.
So you would have to use operator= or swap() to assign bar to foo so that bar's X object gets shared.
Try something like this:
template <typename T, class Deleter = std::default_delete<T> >
class My_Deleter
{
Deleter *chained_deleter;
My_Deleter(std::shared_ptr<T>& p)
: chained_deleter(std::get_deleter<Deleter>(p));
{
}
void operator()(T *ptr) const
{
//...
if (chained_deleter)
(*chained_deleter)(ptr);
}
};
std::shared_ptr<X> foo;
{
std::shared_ptr<X> bar(new X, Deleter);
foo = std::shared_ptr<X>(bar, My_Deleter<X, decltype<Deleter> >(bar));
}
Not sure if this would really work, though. It depends on if/how shared_ptr preserves the original deleter when sharing the same object pointer with a different deleter. I have a feeling that bar's original Deleter might get lost when it goes out of scope and not be safely chainable.
Since the deleter for shared_memory can only safely be set on allocation of the memory, that can't be done. Different shared_ptrs can't have different deleters. And in response to doing some work before going out of scope (the reason for the other deleter), if you want to do some extra work before deleting it, then you can just call a separate function that will do the work before the end of the scope. Check some condition for what you might want and do that work before leaving.
Are there any differences between the two pieces of code below? Is any of them preferable to the other?
operator=
boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo = boost::shared_ptr<Blah>(new Blah()); // Involves creation and copy of a shared_ptr?
reset
boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo.reset(new Blah()); // foo.ptr should point now to a new Blah object
Note: I need to define the shared_ptr and then set it in a different line because I'm using it in a piece of code like:
boost::shared_ptr<Blah> foo;
try
{
foo.reset...
}
foo...
operator= assigns a shared_ptr to a shared_ptr, while reset makes a shared_ptr take ownership of a pointer. So, basically there is no difference between the examples you have posted. That said, you should prefer neither of them and just use make_shared:
foo = boost::make_shared<Blah>();
Also, if possible, you can prevent having to declare a shared_ptr without initialization by wrapping the try-catch block in a separate function that simply returns a shared_ptr to the newly created object:
boost::shared_ptr<Blah> createBlah() {
try {
// do stuff
return newBlah;
}
catch ...
}
operator= takes another shared_ptr as a parameter thus creating another copy (and upping the reference count) while reset() takes a pointer and optionally a deleter, thus in reality creating a new shared_ptr on top of the current one.
reset is equivalent to (and probably implemented as)
void reset(T p, D d)
{
shared_ptr shared(p,d);
swap( shared );
}
operator= is likely to be implemented as:
shared_ptr& operator=( shared_ptr const& other )
{
shared_ptr shared(other);
swap(other);
return *this;
}
The two functions are similar in that they release control of what they are already containing, if any, and manage a different pointer instead.
foo.reset(p) is defined to be equivalent to shared_ptr(p).swap(foo).
Assignment is logically equivalent to copy-and-swap, and possibly implemented that way. So foo = shared_ptr(p); is equivalent to foo.swap(shared_ptr(p)). Possibly with an extra copy in there if the compiler is having a very bad day.
So in the examples you give, I don't think there's much to choose between them. There might be other cases where it matters. But reset does the same template-based capture of the static type of p that the template constructor does, so as far as getting the right deleter is concerned, you're covered.
The main use of assignment is when you want to copy a previously-existing shared_ptr, to share ownership of the same object. Of course it works fine when assigning from a temporary too, and if you look at the different reset overloads they mirror the different constructors. So I suspect you can achieve the same things either way.
Assignment operator create a new shared object from existing one, incrementing the reference count
CSharedObj& CSharedObj::operator=(CSharedObj& r) noexcept
{
if(*this != r){
//detach from the previous ownership
if(0 == dec()) delete m_pControlObj;
//attach to the new control object and increment the reference count
r.inc();
m_pControlObj = r.m_pControlObj;
}
return *this;
}
while the reset call doesn't create the new shared object, but rather a new ownership - attaching to the new underlying pointee ( via control object)
void CSharedObj::reset(Ptr pointee) noexcept
{
//check if this is a last reference-detach from the previous ownership
if(0==dec()) delete m_pControlObj;
// create the ownership over the new pointee (refCnt = 1)
m_pControlObj = new (std::nothrow) CControlObj(pointee);
}
I have a list of smart pointers. I want some of these smart pointers to act as regular pointers, meaning they are simply a reference to an instance and are not involved in its deallocation. They might for example point to instances allocated on the stack. The other smart pointers in the list should act as regular boost::shared_ptr.
Here is how the class might look:
template<class T> smart_ptr {
private:
T *p;
boost::shared_ptr<T> sp;
public:
smart_ptr(T *p): p(p), shared(0) { } // p will not be deleted
smart_ptr(boost::shared_ptr<T> &sp): p(sp.get()), sp(sp) { }
T *get() const { return p; }
}
If there is a boost class that does this, I would prefer to use it instead of writing a class myself. It appears there are none, or am I mistaken?
One constructor for shared_ptr takes the destructor method, and you can pass in an empty functor.
Using Custom Deallocator in boost::shared_ptr
(You want just an empty function.)
I've got this little class in my toolbox for this:
struct nodelete {
template <typename T>
void operator()( T * ) {}
};
Usage:
int main() {
SomeClass sc;
boost::shared_ptr<SomeClass> p( &sc, nodelete() );
// ...
}
This sounds like a boost::weak_ptr:
http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/weak_ptr.htm
But you can only create a weak_ptr from a shared_ptr, so as for your stack-allocated objects, I'm not sure how that would work.
This smells of bad design.
I can't think of a reasonable situation where you wouldn't want to delete the pointer. Here are the (unreasonable IMO) situations:
1) static duration objects. Instead, consider using a singleton mixin (use CRTP to mixin the singleton that has an instance() method that returns a copy of a local static shared_ptr<>; local statics are thread unsafe so you'll also need an appropriate static mutex if this could be called by multiple threads). The benefit of using a proper singleton is that your singleton will be destructed at exit after other objects that continue to hold shared_ptr<>'s to it.
2) objects created on the stack. Just don't do this. Instead create the object on the heap protected by a shared_ptr<>. If you need to create shared_ptr<>'s to the object in different parts of the code (i.e. you can't take copies from an original shared_ptr<>) then inherit from boost::enable_shared_from_this<> and get shared_ptr<>'s from shared_from_this().
Is there some other reason you want a shared_ptr<> that doesn't ever delete anything?
Can boost::shared_ptr release the stored pointer without deleting it?
I can see no release function 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 function unique() 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 by std::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 *