Explicitly deleting a shared_ptr

前端 未结 5 1733
遇见更好的自我
遇见更好的自我 2021-02-01 16:37

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

相关标签:
5条回答
  • 2021-02-01 17:11

    [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.

    0 讨论(0)
  • 2021-02-01 17:14

    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;
    }
    
    0 讨论(0)
  • 2021-02-01 17:19

    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_ptrs 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.

    0 讨论(0)
  • 2021-02-01 17:23

    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.

    0 讨论(0)
  • 2021-02-01 17:29

    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.

    0 讨论(0)
提交回复
热议问题