为什么通过shared_from_this()会导致段故障

Why passing shared_from_this() will cause segment fault?

本文关键字:段故障 故障 from this 为什么 shared      更新时间:2023-10-16

说我们有一个foo定义如下:

// foo.hpp
class Foo;
using FooCallback = std::function<void(std::shared_ptr<Foo> ins)>;
class Foo : public std::enable_shared_from_this<Foo>{
public:
  Foo(int b, const FooCallback& callback):m_bar(b),
                                          m_callback(callback){}
  int
  getBar();
  void
  doSth();
private:
  int m_bar;
  const FooCallback& m_callback;
};

为什么以下代码会导致段错误?

// foo.cpp
#include "foo.hpp"
int
Foo::getBar(){
  return m_bar;
}
void
Foo::doSth(){
  std::cout << "Start ... " << std::endl;
  this->m_callback(shared_from_this());
  std::cout << "End ... " << std::endl;
}
int main()
{
  auto f = std::make_shared<Foo>(100,
        [](std::shared_ptr<Foo> ins){
          std::cout << "bar: " << ins->getBar() << std::endl;
        });
  f->doSth();
  return 0;
}

输出为:

开始...

分割故障

对我的理解,这就是正在发生的事情:

  1. 在main()中, f是一个共享的_ptr,指向foo的实例,例如 ins
  2. 当调用f->doSth()时,ins.doSth()实际上被称为。
  3. 在ins.dosth中,thisins的指针。shared_from_this()ins的共享_ptr。

为什么步骤3引起段故障?

这与shared_from_this无关。如果您在调试器中查看,则表明此segfault位于std::function的内部指针指向的位置。

发生这种情况是因为m_callback是一个参考,并且当您调用doSth(因为它是临时对象)时,它所指的函数对象不再存在。

要解决此问题,您可以按值保存m_callback

const FooCallback m_callback;

甚至更好,由于lambda没有捕获任何东西,因此您可以使m_callback成为普通函数参考(或指针):

using FooCallback = void(std::shared_ptr<Foo> ins);
…
  FooCallback& m_callback;
…
auto f = std::make_shared<Foo>(100,
        *[](std::shared_ptr<Foo> ins){
          std::cout << "bar: " << ins->getBar() << std::endl;
        });