[英]std::enable_shared_from_this with different owner
And yet another enable_shared_from_this question: Basically, I got three things. 还有另一个enable_shared_from_这个问题:基本上,我得到了三件事。
Now, each system should be able to register itself with the EventManager for all kinds of events it is interested in. Moreover, they should be able to de-register themselves for these events if they aren't interested in them any more. 现在,每个系统都应该能够针对其感兴趣的所有事件在EventManager中进行注册。此外,如果他们不再对这些事件感兴趣,则它们应该能够针对这些事件注销自己。
However, I'm not sure how to create systems in the system manager and sign them up in a way that avoids two ownership groups. 但是,我不确定如何在系统管理器中创建系统并以避免两个所有权组的方式对其进行注册。
From the SystemManager: 从SystemManager:
void SystemManager::AddSystem(GameSystem* system)
{
// Take ownership of the specified system.
systems.push_back(std::shared_ptr<GameSystem>(system));
}
From the EventManager: 从EventManager中:
typedef std::shared_ptr<IEventListener> EventListenerPtr;
void EventManager::AddListener(EventListenerPtr const & listener, HashedString const & eventType)
{
// Get the event type entry in the listeners map.
std::map<unsigned long, std::list<EventListenerPtr>>::iterator iterator = this->listeners.find(eventType.getHash());
if (iterator != this->listeners.end())
{
std::list<EventListenerPtr> & eventListeners = iterator->second;
// Add listener.
eventListeners.push_back(listener);
}
else
{
// Add new entry to listeners map, removed for sake of simplicity of this example.
}
}
From some arbitrary system that wants to receive events: 从一些想要接收事件的任意系统中:
void RenderSystem::InitSystem(std::shared_ptr<GameInfrastructure> game)
{
// BAD: Creates second ownership group.
this->game->eventManager->AddListener(std::shared_ptr<IEventListener>(this), AppWindowChangedEvent::AppWindowChangedEventType);
}
I have read my references recommending enable_shared_from_this. 我已经阅读了有关推荐enable_shared_from_this的参考资料。 However, as the systems don't own themselves, they don't have access to the shared_ptr held by the SystemManager who originally created the systems and took ownership of them. 但是,由于系统不拥有自身,因此无法访问由最初创建系统并获得系统所有权的SystemManager持有的shared_ptr。
Any ideas of an elegant way to solve this? 有什么优雅的解决方案的想法吗?
Your first problem is IEventListener
. 您的第一个问题是IEventListener
。 I'm guessing it is an interface to a simple callback. 我猜这是一个简单的回调的接口。
Don't use inheritance for interfaces to simple callbacks, use type erasure on a simple callback. 不要将继承用于简单回调的接口,请在简单回调上使用类型擦除。
typedef std::function<void(EventData)> EventListener;
typedef std::weak_ptr<EventListener> wpEventListener;
typedef std::shared_ptr<EventListener> EventToken;
EventToken EventManager::AddListener(EventListener listener, HashedString const & eventType)
{
// note type changes (3 of them!) -- change the type of this->listeners to match
// probably HashedString should have a std::hash<HashedString> specialization to make this
// less painful
// also should be auto iterator = -- the type of an iterator is not interesting.
std::unordered_map<unsigned long, std::vector<wpEventListener>>::iterator iterator = this->listeners.find(eventType.getHash());
if (iterator != this->listeners.end())
{
auto & eventListeners = iterator->second;
EventToken retval = std::make_shared<EventListener>(std::move(listener));
eventListeners.push_back(retval);
return retval;
} else {
// Add new entry to listeners map, removed for sake of simplicity of this example.
}
}
now when you install Listener, you are responsible to hold your EventToken
until you no longer want to listen to it. 现在,当您安装侦听器时,您有责任持有您的EventToken
直到您不再想要收听它为止。 When you no longer want to listen to it, EventToken.reset()
. 当您不想再听时,可以使用EventToken.reset()
。
In the EventManager
, when you iterate over people listening, do auto listener = it->lock(); if (!listener) continue;
在EventManager
,当您遍历auto listener = it->lock(); if (!listener) continue;
,执行auto listener = it->lock(); if (!listener) continue;
auto listener = it->lock(); if (!listener) continue;
, and in addition do a quick erase-remove-if to remove dead weak_ptr
s. ,此外,还可以执行快速擦除-删除-删除死掉的weak_ptr
。
Now our EventManager
doesn't own the lifetime of its listeners, they can go away (almost) whenever they want. 现在,我们的EventManager
不再拥有其侦听器的生命周期,它们可以(几乎)随时随地消失。 The EventManager
notices the next time an event is invoked, and cleans up the dead ones. EventManager
在下次调用事件时发出通知,并清除失效的事件。
You can retrofit this into using IEventListener
, but even here you'll want a weak pointer, not a shared pointer. 您可以使用IEventListener
进行改造,但即使在这里,您也将需要一个弱指针,而不是共享指针。 Using shared pointers everywhere is going to get you in trouble, as you'll have circular self-supporting references and resource leaks aplenty. 在任何地方使用共享指针都会给您带来麻烦,因为您将拥有循环的自支持引用,并且资源大量泄漏。
Finally, shared_from_this
actually lets you access the shared_ptr
that owns you. 最后, shared_from_this
实际上允许您访问拥有您的shared_ptr
。 It means that when a shared_ptr
is constructed, a weak_ptr
is stored in the shared_from_this
, which can later be extracted even if you only have the this
pointer. 这意味着,在构造shared_ptr
时, weak_ptr
存储在shared_from_this
,即使您只有this
指针,也可以稍后将其提取。
I typically find this a bad sign: you should rarely be upgrading raw pointers to shared pointers in random contexts. 我通常会发现一个不好的迹象:您应该很少在随机上下文中将原始指针升级为共享指针。 The lifetime semantics of a method should be obvious from its interface, and taking a T*
and turning it internally into a shared_ptr<T>
makes the lifetime semantics completely unclear. 方法的生存期语义应该从其接口显而易见,并且将T*
并在内部将其转换为shared_ptr<T>
会使生存期语义完全不清楚。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.