Как я могу использовать std :: enable_shared_from_this в супер и подклассе? - PullRequest
1 голос
/ 17 марта 2020

У меня есть два класса A и B, где B является подклассом A. Мне нужны оба класса, чтобы использовать std::enable_shared_from_this.

Я пробовал это:

#include <memory>
#include <iostream>
#include <vector>


class A : public std::enable_shared_from_this<A> {
  public:
    void insertme(std::vector<std::shared_ptr<A>>& v) {
        std::cout << "A::insertme\n";
        v.push_back(shared_from_this());
        std::cout << "OK\n";
    }
};

class B : public A, public std::enable_shared_from_this<B> {
  public:
    void insertme(std::vector<std::shared_ptr<B>>& v) {
        std::cout << "B::insertme\n";
        v.push_back(std::enable_shared_from_this<B>::shared_from_this());
        std::cout << "OK\n";
    }
};

int main()
{
    std::vector<std::shared_ptr<A>> va;
    std::vector<std::shared_ptr<B>> vb;

    std::shared_ptr<A> pa = std::make_shared<A>();
    std::shared_ptr<B> pb = std::make_shared<B>();

    pa->insertme(va);
    pb->insertme(vb);
}

(Чтобы избежать неоднозначности shared_from_this(), мне пришлось полностью квалифицировать его в B::insertme.)

Когда я запускаю вышеупомянутую программу, я получаю такой вывод:

A::insertme
OK
B::insertme
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr
Aborted (core dumped)

Так что A::insertme работает, а B::insertme - нет.

I Я использую G CC 9.1.0 под Linux.

Что я делаю не так?

Ответы [ 2 ]

3 голосов
/ 17 марта 2020

Вам нужно только (и можно только) наследовать от shared_from_this в базовом классе:

class A : public std::enable_shared_from_this<A> {
  public:
    void insertme(std::vector<std::shared_ptr<A>>& v) {
        std::cout << "A::insertme\n";
        v.push_back(shared_from_this());
        std::cout << "OK\n";
    }
};

class B : public A {
  public:
    void insertme(std::vector<std::shared_ptr<B>>& v) {
        std::cout << "B::insertme\n";
        v.push_back(shared_from_this()->static_pointer_cast<B>());
        std::cout << "OK\n";
    }
};

Это означает, что вам нужен явный static_pointer_cast, чтобы получить shared_ptr<B>, но вы можете обернуть это в переопределение в B, если вы хотите:

std::shared_ptr<B> shared_from_this() { return A::shared_from_this()->static_pointer_cast<B>(); }
0 голосов
/ 17 марта 2020

Автоматическое связывание c с enable_shared_from_this<X>, которое устанавливается при создании shared_ptr<T>, работает только в том случае, если тип класса T наследует ровно одну однозначную базу c enable_shared_from_this. Но B наследует две разные enable_shared_from_this базы.

Вместо этого вы можете иметь только enable_shared_from_this<A> и написать пользовательский B::shared_from_this(), который использует A::shared_from_this():

class B : public A {
  public:
    // These hide the A::shared_from_this(), but they can still be
    // used by qualification if wanted.
    std::shared_ptr<B> shared_from_this()
    { return std::static_pointer_cast<B>(A::shared_from_this()); }
    std::shared_ptr<const B> shared_from_this() const
    { return std::static_pointer_cast<B>(A::shared_from_this()); }

    // ...
};
...