We have a function that returns a new allocated object as a output argument (ref to pointer).
MyFunc(MyObject*& obj)
{
obj = new MyObject();
}
Which is called like so:
Object* obj;
MyFunc(obj);
Internally the function does quite a bit and uses shared_ptr
for memory management. When it is done, the object we would like to return is referenced by a shared_ptr
. I am struggling on how to return our new allocated object as a regular pointer.
We would like to continue to use shared_ptr
internally to reduce risks, but it does not seem to make sense to return a shared_ptr
as the caller takes complete ownership over the returned value (the called function or object no longer needs or keeps a reference to the returned data) and we want them to have flexibility.
Does anyone have any suggestions for allowing us to use shared_ptr
internally but have a regular pointer interface? Thanks
If for some reason you cannot/want not use std::unique_ptr
or std::auto_ptr
(for example if you need to have multiple owners internally during creation for some reason or your underlying methods require std::shared_ptr
to be passed around), you can still make it work with std::shared_ptr
by using custom deleter, as described here: https://stackoverflow.com/a/5995770/1274747
In the principle, after you're done before the return, you switch the deleter to not actually delete the instance (make the deleter "null") and then return by shared_ptr get()
. Even after all shared_ptr objects are destroyed, the memory will not be deleted (as the nulled deleter will skip the deletion).
There is also a link in the comments not so well visible, which might be of your interest: http://paste.ubuntu.com/23866812/ (not sure though if it would really work without the shared ownership of the switch in all cases, would need to test)
As expected, with the linked simple disarmable deleter from the pastebin you need to be careful, because the deleter is actually copied for storing in std::shared_ptr
.
But you can still make it work by using std::ref
:
MyFunc(MyObject*& obj)
{
DisarmableDelete<MyObject> deleter;
std::shared_ptr<MyObject> ptr(new MyObject(), std::ref(deleter));
// do what is necessary to setup the object - protected by deleter
// ...
// disarm before return
deleter._armed = false;
obj = ptr.get();
// deleter disarmed - object not freed
}
And just for completeness (and to avoid a potential future broken link), here is the implementation of DisarmableDelete
from http://paste.ubuntu.com/23866812/.
template <typename T, typename Deleter = typename std::default_delete<T> >
struct DisarmableDelete : private Deleter {
void operator()(T* ptr) { if(_armed) Deleter::operator()(ptr); }
bool _armed = true;
};