Переместится от уникального к общему указателю и инициализирует enable_shared_from_this - PullRequest
0 голосов
/ 18 декабря 2018

Когда я наследую от std::enable_shared_from_this, но создаю unique_ptr, будет ли инициализироваться weak_ptr внутри std::enable_shared_from_this также, когда я "перейду" в shared_ptr на std::move или конструктором перемещения?

Например, что произойдет в следующем коде:

#include <memory>
#include <iostream>

class A : public std::enable_shared_from_this< A >
{
public:
    std::shared_ptr< A > getA()
    {
        return shared_from_this();
    }
};

int main()
{
    std::unique_ptr< A > u(new A());
    // Aborts
    //std::cout << u->getA() << std::endl;
    std::shared_ptr< A > s(std::move(u));
    // Will this work or abort too?
    std::cout << s << ", " << s->getA() << std::endl;
}

Ответы [ 3 ]

0 голосов
/ 18 декабря 2018

[util.smartptr.shared.const] / 1 В приведенных ниже определениях конструктора включает shared_from_this с p для указателя p типа Y*,означает, что если Y имеет однозначный и доступный базовый класс, который является специализацией enable_shared_from_this (23.11.2.5), то remove_cv_t<Y>* должен быть неявно преобразован в T*, и конструктор вычисляет оператор:

if (p != nullptr && p->weak_this.expired())
p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));

template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);

[util.smartptr.shared.const] / 29 Эффекты: ... эквивалентно shared_ptr(r.release(), r.get_deleter())


template<class Y, class D> shared_ptr(Y* p, D d);

[util.smartptr.shared.const] / 10 Эффекты: Создает объект shared_ptr, которому принадлежит объект p и средство удаления d,Когда T не является типом массива, ... включите shared_from_this с помощью p

Так что да, std::shared_ptr< A > s(std::move(u)); правильно инициализирует все, чтобы shared_from_this работал.

0 голосов
/ 18 декабря 2018

Как указали Алан и Игорь, std::weak_ptr<>, реализующий магию shared_from_this(), устанавливается соответствующим образом всякий раз, когда std::shared_ptr<> создается для хранения объекта, публично полученного из std::enable_shared_from_this.Итак, да, ваш код будет работать.

Однако метод-член

std::shared_ptr<A> A::getA()
{
    return shared_from_this();
}

будет вызывать UB (до C ++ 17), если объект не управляется std::shared_ptr<>,К сожалению, до C ++ 17 не было никакого способа сказать изнутри объекта (типа A), управляется ли он с помощью общего указателя, и вы не можете легко предотвратить этот UB.

Поскольку вы фактически используете std::unique_ptr<> для управления своими объектами, я рекомендую поэтому не наследовать от std::enable_shared_from_this.

0 голосов
/ 18 декабря 2018

Согласно https://en.cppreference.com/w/cpp/memory/enable_shared_from_this все конструкторы std::shared_ptr должны инициализировать внутреннюю слабую ссылку, поэтому перемещение std::unique_ptr в std::shared_ptr должно позволить использовать shared_from_this.

Youнужно быть осторожным, чтобы никто не вызывал shared_from_this, в то время как объект принадлежит std::unique_ptr, поскольку это либо неопределенное поведение, либо выдаст std::bad_weak_ptr в зависимости от вашей версии c ++.

...