std :: enable_shared_from_this与其他所有者

尼克·普鲁斯

还有另一个enable_shared_from_这个问题:基本上,我得到了三件事。

  1. 包含应用程序逻辑并且可能是也可能不是事件侦听器的系统类。
  2. 某种EventManager,将事件映射到感兴趣的系统的shared_ptrs。
  3. 某种类型的SystemManager,它具有指向system对象的shared_ptrs的std :: list。

现在,每个系统都应该能够针对其感兴趣的所有类型的事件向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。

有什么优雅的方法可以解决这个问题吗?

Yakk-亚当·内夫罗蒙特

您的第一个问题是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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

从std :: enable_shared_from_this继承

std :: enable_shared_from_this; 公共与私人

std :: enable_shared_from_this :: shared_from_this如何工作

为什么std :: enable_shared_from_this允许多个std :: shared_ptr实例?

为什么 std::enable_shared_from_this 不使用可变的 std::weak_ptr ?

std :: enable_shared_from_this:是否可以在析构函数中调用shared_from_this()?

我们什么时候应该使用std :: enable_shared_from_this

如何在父类和子类中使用std :: enable_shared_from_this?

可以从std :: enable_shared_from_this和抽象基类派生吗?

OS X上std :: enable_shared_from_this <>的编译错误

尝试了解std :: enable_shared_from_this <T>,但使用它会导致bad_weak_ptr

pybind11,在使用 std::enable_shared_from_this 绑定 Trampolines 和多重继承时编译失败

访问std :: recursive_mutex使用的所有者计数器

与其他std容器一起清除std :: queue的模板专业化

django对其他所有者的许可

std :: enable_if和std :: shared_ptr

std :: conditional vs std :: enable_if

std :: apply内部的std :: make_shared

使用std :: move与std :: shared_ptr

其中一个与其他不一样:为什么在所有主要的标准库实现中都使用指针来实现std :: vector :: size?

std :: enable_if <>的错误

std :: shared_ptr删除者类型

带有 std::string 参数的 std::strcpy 和 std::strcat

std :: cout << std :: cin有什么作用?

是否有与std :: array等效的std :: memset?

返回带有std :: move的std :: vector

std :: endl << std :: flush是否有目的?

将所有权从std :: vector转移到std :: shared_ptr

如何取得std :: unique_ptr和std :: shared_ptr的所有权