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

标签 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;
};

为什么下面的代码会导致segment fault?

// 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;
}

输出是:

Start ...

segmentation fault

据我了解,这是正在发生的事情:

  1. 在 main() 中,f 是一个指向 Foo 实例的 shared_ptr,假设它是 ins
  2. 当调用f->doSth()时,实际上调用了ins.doSth()
  3. 在 ins.doSth 中,this 是指向 ins 的指针。 shared_from_this()ins 的 shared_ptr。

那么为什么第 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;
        });

关于c++ - 为什么传递 shared_from_this() 会导致段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42659924/

相关文章:

c++ - 如何为二进制兼容的可扩展性设计 C++ API

c++ - 使用语句和 protected 构造函数

C++:请求超过2GB的内存

c++ - 如何调用 lambda 模板?

c++ - 如何在模板函数中使用enable_shared_from_this?

java - 对象如何存储在内存中 - Java (c++)

c# - LINQ - 查询语法与方法链和 lambda

c++ - 对象构造后 shared_from_this 中的 std::bad_weak_ptr 异常

c++ - enable_shared_from_this - 空的内部弱指针?

lambda - 使用方法引用与HashSet复制