Search code examples
c++shared-ptr

How to wrap a raw pointer into a shared_ptr and prevent shared_ptr from deleting the object?


I need to wrap a raw pointer into a shared_ptr in order to pass it to a function. The function doesn't hold any reference to the input object once it returns.

{
  MyClass i;
  shared_ptr<MyClass> p(&i);
  f(p);
  // BAD: shared_ptr will delete i.
}

How to prevent shared_ptr from deleting the referenced object?


Solution

  • As chris alluded to in the comments, write an empty deleter:

    #include <type_traits>
    
    template <typename T>
    struct empty_delete
    {
        empty_delete() /* noexcept */
        {
        }
    
        template <typename U>
        empty_delete(const empty_delete<U>&,
            typename std::enable_if<
                std::is_convertible<U*, T*>::value
            >::type* = nullptr) /* noexcept */
        {
        }
    
        void operator()(T* const) const /* noexcept */
        {
            // do nothing
        }
    };
    

    Example of use:

    #include <iostream>
    #include <memory>
    
    struct noisy
    {
        noisy() { std::cout << "alive" << std::endl; }
        ~noisy() { std::cout << "dead" << std::endl; }
    
        noisy(const noisy&);
        noisy& operator=(const noisy&);
    };
    
    template <typename T>
    void take(T& yours)
    {
        std::cout << "Taking..." << std::endl;
        {
            auto mine = std::move(yours);
        }
        std::cout << "Took." << std::endl;
    }
    
    int main()
    {
        std::unique_ptr<noisy> a(new noisy());
        std::shared_ptr<noisy> b(new noisy());
        std::unique_ptr<noisy, empty_delete<noisy>> c(new noisy());
        std::shared_ptr<noisy> d(new noisy(), empty_delete<noisy>());
    
        take(a);
        take(b);
        take(c);
        take(d);
    }
    

    Output:

    alive
    alive
    alive
    alive
    Taking...
    dead
    Took.
    Taking...
    dead
    Took.
    Taking...
    Took.
    Taking...
    Took.

    Of course, this example leaks memory.