2017-11-15 9 views
2

이것은 설명하기가 어렵지만 최선을 다할 것입니다. 따라서 RenderComponent, EventManager 및 RenderSystem이 있습니다. 내 RenderComponents 생성자에서 RenderSystem이 구독하는 renderComponentCreated 이벤트를 발생시킵니다. 이벤트 args 객체를 사용하여 renderSystem이 그릴 수있는 정보 (드로어 블, 위치 및 유형)가 포함 된 데이터로 RenderNode를 전달합니다.고유 한 소유권 (일종의)으로 shared_ptr을 사용하는 것이 좋습니다.

지금까지 그렇게 좋았습니다. 이제는 renderComponent가 삭제 될 때 RenderNode가 RenderSystem에서 자동으로 제거되기를 원하면서 동시에 수동으로 제거하는 옵션을 남겨 둡니다. 어떤 사건에 대한 반응으로 이것은 RenderSystem이 다시 구독하는 RenderComponentRemoveNodeEvent를 사용하여 수행 할 수 있습니다.

이제 '문제'. 내 이해 (그리고 내가 원하는)에서 renderNode는 RenderComponent (따라서 unique_ptr)가 고유하게 소유해야합니다. 그러나이 작업을 수행하려면 renderNode에 대한 비교 연산자를 구현하여 복사 (또는 제거 할 때 찾을 수 있도록)하거나 renderNode에 대한 참조/원시 포인터를 전달해야합니다. 그러나 (내가 맞다면) 참조가 여전히 자동 제거를 구현할 수 없다는 것을 의미하는 유효한 객체를 참조하는지 여부를 알 수있는 방법이 없습니다.

내 솔루션 공유 RenderNode (즉 고유 RenderComponent에 의해 소유)하고 이벤트에 약한 포인터를 전달했다. 또한 RenderSystem은 여전히 ​​유효한 객체를 가리키고 있는지 여부를 확인하고 그렇지 않은 경우 자동으로 제거하는 weak 포인터 목록을 관리합니다. 그래서 본질적으로 내가 원했던 것은 고유 한 것에서 약한 포인터를 만드는 것입니다. 그러나 현재와 같이 누군가가 약한 포인터에서 공유 포인터를 만들고 RenderNode를 오래 유지해야합니다. 관리 객체 자체 (RenderNode)에는 RenderComponent보다 오래 존재하지 않는 다른 객체에 대한 참조가 포함되어 있으므로 심각한 문제가 발생할 수 있습니다.

지금 내 질문 : 좋은 디자인으로 간주 될 수 있습니까, 아니면 놓친 것이 있습니까?

PS :이 설명이 당신의 도움을 투박한 비트 (영어 내 기본 없음) 및 감사를 읽는 경우 죄송합니다! 파괴 될 수있는 객체에 대한 액세스 권한을 부여 std::weak_ptr를 사용하여 아무 문제가 확실히 없습니다

+0

이 게임에 대한인가 :

template<class Derived> class HandleBased { public: typedef uint64_t handle_t; HandleBased() : m_Handle(NextHandle()) { Map()[m_Handle] = this; } ~HandleBased() { auto it = Map().find(m_Handle); Map().erase(it); } handle_t ThisHandle() { return m_Handle; } static Derived* FindPtr(handle_t h) { auto it = Map().find(h); if (it == Map().end()) return null_ptr; return static_cast<Derived*>(it->second); } private: static handle_t NextHandle() { static handle_t next = 0; return next++; } static std::unordered_map<handle_t, HandleBased*>& Map() { static std::unordered_map<handle_t, HandleBased*> the_map; return the_map; } handle_t m_Handle; }; 

그리고 여기 당신이 그것을 사용하는 거라고하는 방법의 예? – arynaq

+0

@arynaq 네 게임 엔진 ^^ –

+0

가능한 솔루션 (많은 게임 엔진에서 사용되는)은 ObjectID를 사용하여 (다른 시스템이 소유 한 구성 요소를 검색하고 참조 할 수있는) "맵"을 갖는 것입니다. "전체"참조를 전달해야합니다 (그리고 ObjectID는 저장하기에 안전합니다). – UnholySheep

답변

2

, 즉 그것을 위해 발명 된 것입니다. 그러나 객체 자체가 std::shared_ptr에 의해 유지되어야합니다. 이 객체는 부모에 의해 객체 수명이 제어되도록하려는 의도를 숨길뿐만 아니라 객체의 동적 할당을 강제 실행하고 부모 객체의 멤버 변수가 될 수 없도록합니다.

또 다른 방법은 핸들을 통해 포인터를 추적하고, 객체가 생사 추적하는 핸들 매니저를하는 것입니다. 이것을 구현하는 가장 안전한 방법은 추적하는 객체의 기본 클래스를 RAII가 항상 최신 상태로 유지하도록하는 것입니다. 이 개념의 샘플 구현은 다음과 같습니다. 참고 : 테스트되지 않았습니다.

class RenderNode : public HandleBased<RenderNode> 
{ 
}; 

class RenderComponent 
{ 
    std::unique_ptr<RenderNode> node1; 
    RenderNode node2; 

public: 
    void Setup(RenderSystem& rs) 
    { 
     node1 = new RenderNode; 
     rs.nodes.push_back(node1->ThisHandle()); 
     rs.nodes.push_back(node2.ThisHandle()); 
    } 
}; 

class RenderSystem 
{ 
public: 
    std::list<RenderNode::Handle> nodes; 

    void DoRender() 
    { 
     for (auto it = nodes.begin(); it != nodes.end();) 
     { 
      RenderNode* p = RenderNode::FindPtr(*it); 
      if (p == NULL) 
       it = nodes.erase(it); 
      else 
      { 
       p->DoSomething(); 
       ++it; 
      } 
     } 
    } 
}; 
관련 문제