为什么传递shared_from_this()会导致段错误?

时间:2017-03-07 22:56:43

标签: c++ lambda shared-ptr

假设我们有一个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是指向Foo实例的shared_ptr,比如它是ins
  2. 调用f->doSth()时,实际上会调用ins.doSth()
  3. 在ins.doSth中,this是指向ins的指针。 shared_from_this()ins的shared_ptr。
  4. 那么为什么步骤3导致段故障?

1 个答案:

答案 0 :(得分:3)

这与shared_from_this无关。如果您查看调试器,它会在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;
        });