Conversion from boost::shared_ptr to std::shared_ptr?

Based on janm's response at first I did this:

template<class T> std::shared_ptr<T> to_std(const boost::shared_ptr<T> &p) {
    return std::shared_ptr<T>(p.get(), [p](...) mutable { p.reset(); });
}

template<class T> boost::shared_ptr<T> to_boost(const std::shared_ptr<T> &p) {
    return boost::shared_ptr<T>(p.get(), [p](...) mutable { p.reset(); });
}

But then I realized I could do this instead:

namespace {
    template<class SharedPointer> struct Holder {
        SharedPointer p;

        Holder(const SharedPointer &p) : p(p) {}
        Holder(const Holder &other) : p(other.p) {}
        Holder(Holder &&other) : p(std::move(other.p)) {}

        void operator () (...) { p.reset(); }
    };
}

template<class T> std::shared_ptr<T> to_std_ptr(const boost::shared_ptr<T> &p) {
    typedef Holder<std::shared_ptr<T>> H;
    if(H *h = boost::get_deleter<H>(p)) {
        return h->p;
    } else {
        return std::shared_ptr<T>(p.get(), Holder<boost::shared_ptr<T>>(p));
    }
}

template<class T> boost::shared_ptr<T> to_boost_ptr(const std::shared_ptr<T> &p){
    typedef Holder<boost::shared_ptr<T>> H;
    if(H * h = std::get_deleter<H>(p)) {
        return h->p;
    } else {
        return boost::shared_ptr<T>(p.get(), Holder<std::shared_ptr<T>>(p));
    }
}

This solution leaves no reason for not using it without restrictions since you get the original pointer back if you convert back to the original type.


Update to an "off the top of my head" answer, almost eleven years later:

As pointed out in this answer, an implementation is allowed to extend the lifetime the deleter beyond the lifetime of the shared_ptr. For example, until after all weak_ptr instances are also destroyed. This would cause a problem where the presence of weak_ptr instances prevent the destruction of the underlying object, obviously a problem.

To avoid this, either use the approach in the answer by @Fozi with an explicit call to reset(), or the aliasing constructor approach in the linked answer.

Original Answer:

You can carry the boost::shared_ptr "inside" the std::shared_ptr by using the destructor to carry the reference around:

template<typename T>
void do_release(typename boost::shared_ptr<T> const&, T*)
{
}

template<typename T>
typename std::shared_ptr<T> to_std(typename boost::shared_ptr<T> const& p)
{
    return
        std::shared_ptr<T>(
                p.get(),
                boost::bind(&do_release<T>, p, _1));

}

The only real reason to do this is if you have a bunch of code that expects std::shared_ptr<T>.