使用enable_shared_from_this时bad_weak_ptr

bad_weak_ptr when using enable_shared_from_this

提问人:Rodrigo 提问时间:10/31/2023 最后编辑:Rodrigo 更新时间:10/31/2023 访问量:97

问:

我有一个基类

class eventreceiver {
public:
  eventreceiver() = default;
  virtual ~eventreceiver() = default;

  virtual void on_quit();
}

我有一个使用它的类

class engine : public eventreceiver, std::enable_shared_from_this<engine> {
public:
  virtual ~engine() = default;

  [[nodiscard]] static std::shared_ptr<engine> create();

  void init(std::string_view title, int32_t width, int32_t height, bool fullscreen = false);

  void add_loopable(std::shared_ptr<loopable> loopable);

  void run();

protected:
  virtual void on_quit() override;

private:
  engine() = default;

  bool _running;

  std::list<std::shared_ptr<loopable>> _loopables;
  std::shared_ptr<window> _window;
  std::shared_ptr<renderer> _renderer;
  std::shared_ptr<eventmanager> _eventmanager;
};

当我试图从下面传递shared_ptr时shared_from_this

void engine::init(std::string_view title, int32_t width, int32_t height, bool fullscreen) {
  _running = true;
  _window = std::make_shared<window>(title, width, height, fullscreen);
  _renderer = _window->create_renderer();
  _eventmanager = std::make_shared<eventmanager>();

  _eventmanager->add_receiver(std::dynamic_pointer_cast<eventreceiver>(shared_from_this())); // HERE

  add_loopable(std::make_shared<framerate>());
}

我收到异常。bad_weak_ptr

我做错了什么,我怎样才能将“引擎”的shared_ptr传递给“_eventmanager”?

编辑:最小可重复示例->https://onlinegdb.com/4VTq1mMnc

C++ C++17 标准

评论

2赞 Eljay 10/31/2023
一个最小的可重现示例将是最有帮助的,因为这样我们就可以运行您的代码并查看问题。我会使用调试器。但是,唉,这段代码无法编译——它是不完整的。我无法将其复制并粘贴到并编译并运行它。对于初学者来说,它不见了。我可以填补空白,但我怀疑如果我这样做,我很有可能不会重新创建错误。a.cpp#include <memory>
1赞 Yksisarvinen 10/31/2023
1.不要做,你不需要任何特别的东西来投射(如果你需要改变它并忘记演员阵容,这可能会很危险)。2. 有问题的实例是否用 ?std::dynamic_pointer_castenginestd::shared_ptr
0赞 Rodrigo 10/31/2023
@Eljay这里是 MRE onlinegdb.com/4VTq1mMnc
0赞 Rodrigo 10/31/2023
@Yksisarvinen没有 DPC 我无法传递给该函数,因为它需要std::shared_ptr<eventreceiver>
0赞 Yksisarvinen 10/31/2023
@Rodrigo 是的,您可以: godbolt.org/z/jsvcrxq5W。指向派生类的智能指针可隐式转换为指向基类的智能指针(就像常规指针一样)。

答:

4赞 Yksisarvinen 10/31/2023 #1

shared_from_this() 只有在由 管理时才能调用。thisshared_ptr

这是行不通的:

engine e;
e.init();

这将起作用:

std::shared_ptr<engine> e = engine::create();
e->init();

在不相关的说明中,您应该避免它是智能指针对应部分。特别是,这里不需要强制转换:is implicically convertable to(就像 is implicitly convertable to 一样)。dynamic_caststd::dynamic_pointer_caststd::shared_ptr<Derived>std::shared_ptr<Base>Derived*Base*

评论

0赞 Rodrigo 10/31/2023
如果我执行你在 godbolt 上共享的代码,它也会给我一个糟糕的弱 ptr。而且我应用了你的建议,但仍然有不好的弱 ptr。
4赞 Marek R 10/31/2023 #2

您不能共享指向在堆栈上创建的内容的指针! 您以无效的方式构建。任何继承的东西都应该在堆上分配。enginestd::enable_shared_from_this

最好的方法是 std:make_shared:

int main()
{
    auto e = std::make_shared<engine>();
    e->init();

    return 0;
}

https://godbolt.org/z/bdjs67P5Y

请注意,您之前忘记了关键字!没有这个是行不通的。publicstd::enable_shared_from_this<engine>shared_from_this

2赞 molbdnilo 10/31/2023 #3

首先,您只能与已共享的对象一起使用。shared_from_this

你需要

auto e = std::make_shared<engine>();
e->init();

其次,很容易忘记继承的显式访问保护必须单独应用于每个基类。

public eventreceiver, std::enable_shared_from_this<engine>

私下继承自 ,这使得机器变得 BOOM。std::enable_shared_from_this<engine>

你需要

public eventreceiver, public std::enable_shared_from_this<engine>

而且你不需要搞砸铸造。