还有另一个enable_shared_from_这个问题:基本上,我得到了三件事。
现在,每个系统都应该能够针对其感兴趣的所有类型的事件向EventManager注册。此外,如果它们不再对这些事件感兴趣,则它们应该能够为这些事件取消注册。
但是,我不确定如何在系统管理器中创建系统并以避免两个所有权组的方式对其进行注册。
从SystemManager:
void SystemManager::AddSystem(GameSystem* system)
{
// Take ownership of the specified system.
systems.push_back(std::shared_ptr<GameSystem>(system));
}
从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.
}
}
从某些想要接收事件的任意系统中:
void RenderSystem::InitSystem(std::shared_ptr<GameInfrastructure> game)
{
// BAD: Creates second ownership group.
this->game->eventManager->AddListener(std::shared_ptr<IEventListener>(this), AppWindowChangedEvent::AppWindowChangedEventType);
}
我已经阅读了有关推荐enable_shared_from_this的参考资料。但是,由于系统不拥有自身,因此无法访问最初创建系统并获得系统所有权的SystemManager所拥有的shared_ptr。
有什么优雅的方法可以解决这个问题吗?
您的第一个问题是IEventListener
。我猜这是一个简单的回调的接口。
不要将继承用于简单回调的接口,请在简单回调上使用类型擦除。
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.
}
}
现在,当您安装侦听器时,您有责任持有您的侦听器,EventToken
直到您不再想要收听它为止。当您不再想听时,EventToken.reset()
。
在中EventManager
,当您遍历正在收听的人时,请执行auto listener = it->lock(); if (!listener) continue;
,此外,还可以执行快速擦除-移除-if来删除死weak_ptr
点。
现在,我们EventManager
不再拥有其听众的生命,他们可以随时随地消失(几乎)。该EventManager
注意到在下次调用的事件,并清理死的。
您可以将其改编为using IEventListener
,但即使在这里,您也将需要一个弱指针,而不是共享指针。在任何地方使用共享指针都会给您带来麻烦,因为您将拥有循环的自我支持的引用,并且大量的资源泄漏。
最后,shared_from_this
实际上可以让您访问shared_ptr
拥有您的。这意味着在shared_ptr
构造a时,aweak_ptr
存储在中shared_from_this
,即使您只有this
指针,也可以稍后将其提取。
我通常觉得这是一个不好的信号:您应该很少在随机上下文中将原始指针升级为共享指针。方法的生存期语义应该从其接口显而易见,而将aT*
并在内部将其转换为ashared_ptr<T>
会使生存期语义完全不清楚。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句