Преобразование из boost :: shared_ptr в std :: shared_ptr? - PullRequest
39 голосов
/ 13 июня 2011

Я получил библиотеку, которая внутренне использует версию Boost shared_ptr и предоставляет только те. Для моего приложения я хотел бы использовать std::shared_ptr всякий раз, когда это возможно. К сожалению, прямого преобразования между этими двумя типами нет, так как подсчет ссылок зависит от реализации.

Есть ли способ, чтобы и boost::shared_ptr, и std::shared_ptr использовали один и тот же объект ref-count? Или, по крайней мере, украсть ref-count из Boost-версии и позволить версии stdlib позаботиться об этом?

Ответы [ 2 ]

35 голосов
/ 26 сентября 2012

Сначала, основываясь на ответе janm, я сделал это:

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(); });
}

Но потом я понял, что могу сделать это вместо этого:

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));
    }
}

Это решение не оставляет оснований не использовать егобез ограничений, поскольку вы возвращаете исходный указатель, если преобразовываете обратно в исходный тип.

29 голосов
/ 13 июня 2011

Вы можете нести boost :: shared_ptr «внутри» std :: shared_ptr, используя деструктор для переноса ссылки:

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));

}

Единственная реальная причина сделать это, если у вас есть код, который ожидает std::shared_ptr<T>.

...