Simple question here: are you allowed to explicitly delete a boost::shared_ptr
yourself? Should you ever?
Clarifying, I don\'t mean delete the pointer held
[Edit: you can delete
a shared_ptr
if and only if it was created with new
, same as any other type. I can't think why you'd create a shared_ptr
with new
, but there's nothing stopping you.]
Well, you could write delete ptr.get();
.
Doing so leads almost inevitably to undefined behavior either when the other shared owners use their shared_ptr
to access the now-deleted object, or the last shared_ptr
to the object is destroyed, and the object gets deleted again.
So no, you shouldn't.
The purpose of shared_ptr
is to manage an object that no one "person" has the right or responsibility to delete, because there could be others sharing ownership. So you shouldn't ever want to, either.
Expliticly deleting comes in handy in some (very?) rare cases.
In addition to explicitly deleting, sometimes you HAVE to explicitly destruct a shared pointer when you are 'deleting' it!
Things can get weird when interfacing with C code, passing a shared_ptr as an opaque value.
For example I have the following for passing objects to and from the Lua scripting language which is written in C. (www.lua.org)
static void push( lua_State *L, std::shared_ptr<T> sp )
{
if( sp == nullptr ) {
lua_pushnil( L );
return;
}
// This is basically malloc from C++ point of view.
void *ud = lua_newuserdata( L, sizeof(std::shared_ptr<T>));
// Copy constructor, bumps ref count.
new(ud) std::shared_ptr<T>( sp );
luaL_setmetatable( L, B::class_name );
}
So thats a shared_ptr in some malloc'd memory. The reverse is this... (setup to be called just before Lua garbage collects an object and 'free's it).
static int destroy( lua_State *L )
{
// Grab opaque pointer
void* ud = luaL_checkudata( L, 1, B::class_name );
std::shared_ptr<T> *sp = static_cast<std::shared_ptr<T>*>(ud);
// Explicitly called, as this was 'placement new'd
// Decrements the ref count
sp->~shared_ptr();
return 0;
}
Your question isn't clear. If you've allocated a shared_ptr
dynamically then you're certainly allowed to delete
it whenever you want.
But if you're asking whether you're allowed to delete whatever object is being managed by the shared_ptr
, then the answer is ... it depends. If shared_ptr::unique
returns true, then calling shared_ptr::reset
will delete the managed object. However, if shared_ptr::unique
returns false, it means there are more than one shared_ptr
s sharing ownership of that object. In this case a call to reset
will only result in the reference count being decremented by 1, actual deletion of the object will take place when the last shared_ptr
managing that object either goes out of scope or is itself reset
.
EDIT:
After your edit, it seems you are asking about deleting a dynamically allocated shared_ptr
. Something like this:
auto sp = new boost::shared_ptr<int>( new int(42) );
// do something with sp
delete sp;
This is allowed and will work as expected, although it would be an unusual use case. The only caveat is that if in between the allocation and deletion of sp
you create another shared_ptr
that shares ownership of the object, deleting sp
will not result in deletion of the object, that will only happen when the reference count for the object goes to 0.
If you want to simulate the count decrement, you can do it manually on the heap like so:
int main(void) {
std::shared_ptr<std::string>* sp = new std::shared_ptr<std::string>(std::make_shared<std::string>(std::string("test")));
std::shared_ptr<std::string>* sp2 = new std::shared_ptr<std::string>(*sp);
delete sp;
std::cout << *(*sp2) << std::endl; // test
return 0;
}
Or on the stack using std::shared_ptr::reset()
like so:
int main(void) {
std::shared_ptr<std::string> p = std::make_shared<std::string>(std::string("test"));
std::shared_ptr<std::string> p2 = p;
p.reset();
std::cout << *p2 << std::endl; // test
return 0;
}
But it's not that useful.
You cannot force its reference count to zero, no.
Think about what would be required for that to work. You would need to go to each place the shared_ptr is used and clear it.
If you did force the shared pointer to delete and set it to NULL, it would be just like a weak_ptr. However, all those places in the code using that shared_ptr are not ready for that and expect to be holding a valid pointer. They have no reason to check for NULL, and so those bits of code would crash.