[英]std::enable_shared_from_this with different owner
还有另一个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;
,执行auto listener = it->lock(); if (!listener) continue;
auto listener = it->lock(); if (!listener) continue;
,此外,还可以执行快速擦除-删除-删除死掉的weak_ptr
。
现在,我们的EventManager
不再拥有其侦听器的生命周期,它们可以(几乎)随时随地消失。 EventManager
在下次调用事件时发出通知,并清除失效的事件。
您可以使用IEventListener
进行改造,但即使在这里,您也将需要一个弱指针,而不是共享指针。 在任何地方使用共享指针都会给您带来麻烦,因为您将拥有循环的自支持引用,并且资源大量泄漏。
最后, shared_from_this
实际上允许您访问拥有您的shared_ptr
。 这意味着,在构造shared_ptr
时, weak_ptr
存储在shared_from_this
,即使您只有this
指针,也可以稍后将其提取。
我通常会发现一个不好的迹象:您应该很少在随机上下文中将原始指针升级为共享指针。 方法的生存期语义应该从其接口显而易见,并且将T*
并在内部将其转换为shared_ptr<T>
会使生存期语义完全不清楚。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.