簡體   English   中英

std :: enable_shared_from_this與其他所有者

[英]std::enable_shared_from_this with different owner

還有另一個enable_shared_from_這個問題:基本上,我得到了三件事。

  1. 包含應用程序邏輯並且可能是也可能不是事件偵聽器的系統類。
  2. 某種EventManager,將事件映射到感興趣的系統的shared_ptrs。
  3. 某種類型的SystemManager,它擁有std :: list到系統對象的shared_ptrs。

現在,每個系統都應該能夠針對其感興趣的所有事件在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM