Search code examples
c++11shared-ptrboost-multi-index

how to use reset with const shared pointer to non const object?


I am trying to reset shared pointer which is member of struct coming from iterator of container with constant structs"elements".
the code does not compile, with error:

cannot convert 'this' pointer from 'const boost::shared_ptr<boost::log::v2s_mt_nt6::sinks::text_file_backend>' to 'boost::shared_ptr<boost::log::v2s_mt_nt6::sinks::text_file_backend> &'

this error tells me that const shared pointer is not allowed to be used by reset??!! is this true?
if so how can i cast this const shared pointer into non const to be used by reset??


Solution

  • Do not attemps to do anything that could delete the pointer hold by a const shared_ptr<T>, like calling reset() on it!

    If you do something like delete myConstSharedPtr.get();, delete will get called again on the stored pointer when the reference count will reach 0, basically causing a double free error.

    Also, you should reconsider your design and decide wether shared_ptr is really what you want to use here.


    Ultimately, as a very last resort, if the const'ness of this shared_ptr comes from an external library which should not impose this const restriction and which you cannot properly patch, then const_cast is made for such situation. But forget it, you don't want to use that, really.

    Still there ? Here is how to use const_cast to force reset a const shared_ptr.

    template<typename T>
    void forceReset(const std::shared_ptr<T> ptr){
       const_cast<std::shared_ptr<T>&>(ptr).reset();
    }
    

    WARNING: If this code does what you want at first sight, it means that the bad library you depend on leaks memory. Indeed, there is no way to detach a shared_ptr, that is, destroying it without updating the reference count. It means that unless one of the shared pointer referring to the force-deleted resource is dynamically allocated and never deleted until the end of the program, a double free will occur resulting in undefined behaviour... likely a nasty crash.

    But if you still want to proceed, which you should definitely not, you could take advantage of that to prevent the reference counter to reach zero at the cost of a small memory leak which will be cleaned-up at program exit. Leaking memory will not lead to any kind of undefined behavior.

    template<typename T>
    void forceReset(const std::shared_ptr<T> ptr){
       //This leaked shared_ptr will prevent automatic deletion
       new std::shared_ptr<T>(ptr);
       const_cast<std::shared_ptr<T>&>(ptr).reset();
    }
    

    Just another disclaimer: I strongly discourage anyone to use this hack. I gave it to discuss the risk of messing with smart pointers and const_cast. Please, consider one more time patching the offending library or using another one.