我在阅读 Boost.Asio 示例和阅读文档后遇到了 enable_shared_from_this
我仍然不知道应该如何正确使用它。有人可以给我一个例子和解释什么时候使用这个类是有意义的。
原文由 fido 发布,翻译遵循 CC BY-SA 4.0 许可协议
我在阅读 Boost.Asio 示例和阅读文档后遇到了 enable_shared_from_this
我仍然不知道应该如何正确使用它。有人可以给我一个例子和解释什么时候使用这个类是有意义的。
原文由 fido 发布,翻译遵循 CC BY-SA 4.0 许可协议
在一种特殊情况下,我发现 enable_shared_from_this
非常有用:使用异步回调时的线程安全。
想象类 Client
有一个类型为 AsynchronousPeriodicTimer
的成员:
struct AsynchronousPeriodicTimer
{
// call this periodically on some thread...
void SetCallback(std::function<void(void)> callback);
void ClearCallback(); // clears the callback
}
struct Client
{
Client(std::shared_ptr< AsynchronousPeriodicTimer> timer)
: _timer(timer)
{
_timer->SetCallback(
[this]
()
{
assert(this); // what if 'this' is already dead because ~Client() has been called?
std::cout << ++_counter << '\n';
}
);
}
~Client()
{
// clearing the callback is not in sync with the timer, and can actually occur while the callback code is running
_timer->ClearCallback();
}
int _counter = 0;
std::shared_ptr< AsynchronousPeriodicTimer> _timer;
}
int main()
{
auto timer = std::make_shared<AsynchronousPeriodicTimer>();
{
auto client = std::make_shared<Client>(timer);
// .. some code
// client dies here, there is a race between the client callback and the client destructor
}
}
客户端类为周期性计时器订阅回调函数。一旦客户端对象超出范围,客户端的回调和客户端的析构函数之间就会出现竞争条件。可以使用悬空指针调用回调!
解决方案:使用 enable_shared_from_this
在回调调用期间延长对象生命周期。
struct Client : std::enable_shared_from_this<Client>
{
Client(std::shared_ptr< AsynchronousPeriodicTimer> timer)
: _timer(timer)
{
}
void Init()
{
auto captured_self = weak_from_this(); // weak_ptr to avoid cyclic references with shared_ptr
_timer->SetCallback(
[captured_self]
()
{
if (auto self = captured_self.lock())
{
// 'this' is guaranteed to be non-nullptr. we managed to promote captured_self to a shared_ptr
std::cout << ++self->_counter << '\n';
}
}
);
}
~Client()
{
// the destructor cannot be called while the callback is running. shared_ptr guarantees this
_timer->ClearCallback();
}
int _counter = 0;
std::shared_ptr< AsynchronousPeriodicTimer> _timer;
}
enable_shared_from_this
的机制,结合 std::shared_ptr
引用计数固有的线程安全,使我们能够保证 Client
对象不能被破坏而回调代码被破坏访问其内部成员。
注意 Init
方法与构造函数是分开的,因为 enable_shared_from_this
的初始化过程直到构造函数退出才完成。因此,额外的方法。从构造函数中订阅异步回调通常是不安全的,因为回调可能会访问未初始化的字段。
原文由 Elad Maimoni 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.5k 阅读
3 回答486 阅读✓ 已解决
它使您能够获得有效的
shared_ptr
实例到this
,而您所拥有的只是this
。没有它,您将无法获得shared_ptr
到this
,除非您已经有一个会员。此示例来自 enable_shared_from_this 的 boost 文档:方法
f()
返回一个有效的shared_ptr
,即使它没有成员实例。请注意,您不能简单地这样做:此返回的共享指针将具有与“正确”的引用计数不同的引用计数,并且当对象被删除时,其中一个最终将丢失并持有一个悬空引用。
enable_shared_from_this
已成为 C++ 11 标准的一部分。您也可以从那里以及从 boost 中获取它。