简体   繁体   English

std :: enable_shared_from_this与其他所有者

[英]std::enable_shared_from_this with different owner

And yet another enable_shared_from_this question: Basically, I got three things. 还有另一个enable_shared_from_这个问题:基本上,我得到了三件事。

  1. System classes that contain application logic and might or might not be event listeners. 包含应用程序逻辑并且可能是也可能不是事件侦听器的系统类。
  2. Some kind of EventManager, that maps events to shared_ptrs of interested systems. 某种EventManager,将事件映射到感兴趣的系统的shared_ptrs。
  3. Some kind of SystemManager, that holds a std::list of shared_ptrs to System objects. 某种类型的SystemManager,它拥有std :: list到系统对象的shared_ptrs。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM