为什么传递 shared_from_this() 会导致段错误?
Why passing shared_from_this() will cause segment fault?
假设我们有一个 class 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;
}
输出为:
Start ...
segmentation fault
据我了解,情况是这样的:
- 在main()中,
f
是一个指向Foo实例的shared_ptr,假设是ins
.
- 调用
f->doSth()
时,实际上调用了ins.doSth()
。
- 在ins.doSth中,
this
是指向ins
的指针。 shared_from_this()
是 shared_ptr 到 ins
.
那么为什么第 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;
});
假设我们有一个 class 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;
}
输出为:
Start ...
segmentation fault
据我了解,情况是这样的:
- 在main()中,
f
是一个指向Foo实例的shared_ptr,假设是ins
. - 调用
f->doSth()
时,实际上调用了ins.doSth()
。 - 在ins.doSth中,
this
是指向ins
的指针。shared_from_this()
是 shared_ptr 到ins
.
那么为什么第 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;
});