为什么要使用 std::enable_shared_from_this,以及使用场景
为什么要使用 std::enable_shared_from_this
当使用原始指针构造或者初始化一个
shared_ptr
时,将会创建一个新的控制块。为了确保一个对象仅由一个共享的控制块管理,必须通过复制已存在的shared_ptr
对象来创建一个新的shared_ptr
实例。但是在某些情况下,
shared_ptr
管理的对象需要为自己获取shared_ptr
,类似于下面这样尝试从自身指针创建shared_ptr
的方式是行不通的:
1
2
3
4
5
6
7
8
9
10
11
struct Egg {
std::shared_ptr<Egg> get_self_ptr() {
return std::shared_ptr<Egg>(this);
}
};
void spam() {
auto sp1 = std::make_shared<Egg>();
auto sp2 = sp1->get_self_ptr(); // undefined behavior
// sp1 and sp2 have two different control blocks managing same Egg
}
- 类似下面这样,在类内部持有自身的
shared_ptr
对象导致其释放不了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <memory>
#include <boost/core/ignore_unused.hpp>
struct Immortal {
std::shared_ptr<Immortal> self;
~Immortal() {
std::cout << "dtor of Immortal called. self.use_count() = " << self.use_count() << std::endl;
// self.reset(); // (1)
}
};
int main(int argc, char* argv[]) {
boost::ignore_unused(argc, argv);
auto immortal = new Immortal();
immortal->self = std::shared_ptr<Immortal>(immortal);
std::cout << "main exit. immortal->self.use_count() = " << immortal->self.use_count() << std::endl;
// delete immortal; (2)
return 0;
}
log 输出:
1
main exit. immortal->self.use_count() = 1
如果恢复(1),(2)两处代码,导致同样多次析构出错。
测试代码 test_enable_shared_from_this。
- 为了解决这个问题,我们就需要用到
std::enable_shared_from_this
。public
继承std::enable_shared_from_this
的类中可以通过调用shared_from_this()
方法来获取自身的shared_ptr
。
1
2
3
4
5
6
7
8
struct Thing;
void some_api(const std::shared_ptr<Thing>& tp);
struct Thing : public std::enable_shared_from_this<Thing> {
void method() {
some_api(shared_from_this());
}
};
std::enable_shared_from_this 的使用场景
创建异步任务,并且需要把自身的shared_ptr
传给异步任务,此时适用于使用 std::enable_shared_from_this
。
不使用 std::enable_shared_from_this,使用 std::weak_ptr 替代的解决办法
weak_ptr
是一种弱引用,它不会影响受管理对象的生命周期,但是在需要时可以用来获取强引用。 如果一个对象持有自身的weak_ptr
,那么在需要的时候,就可以获取自身的shared_ptr
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Naive {
public:
static std::shared_ptr<Naive> create() {
auto sp = std::shared_ptr<Naive>(new Naive);
sp->weak_self_ = sp;
return sp;
}
auto async_method() {
return std::async(std::launch::async, [self = weak_self_.lock()]() {
self->do_something();
});
}
void do_something() {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
private:
Naive() = default;
Naive(const Naive&) = delete;
const Naive& operator=(const Naive&) = delete;
std::weak_ptr<Naive> weak_self_;
};
void test() {
std::future<void> ft; {
auto pn = Naive::create();
ft = pn->async_method();
}
ft.get();
}
参考
本文由作者按照 CC BY 4.0 进行授权