2012-03-07 2 views
1

나는 작동하는 클래스의 템플릿을 작성하고 있는데 이는 바보 같은 질문 일 수 있습니다.하지만 템플릿 구조 (링크 된 목록)가 객체에 대한 포인터를 보유하고 있다면 어떻게 알 수 있습니까? 삭제되고 있는지, 또는 포인터가 처음부터 어디에 있는지?템플릿 형식이 동적인지 확인

예 : LinkedList의은

클래스 것은의 객체에 대한 포인터

열거 내부 노드 안에 배치되는 LinkedList의 내부 노드의 내부에 배치되어이 프로그램에 2 가지 방법으로 사용될 a linked list

노드가 삭제된다는 것을 알고 있지만 노드의 내용이 포인터이므로 삭제할 수 있고 Null 참조 된 객체가 아니라는 것을 어떻게 알 수 있습니까?

+0

다른 유형의 링크 된 목록을 만들려고하십니까? – Xeo

+0

올바르게 이해하고 있는지 확인하기 위해 LinkedList 을 가지고 있고 그 안에 Blah *를 넣고 LinkedList를 자동으로 소멸시키고 연결된 목록의 내용이 가리키는 모든 객체를 해제 할 수 있습니까? 이것은 수업이하지 말아야하는 것처럼 보입니다. 개체를 활성 상태로 유지하고 목록에 밀어 넣었 으면 목록이 삭제됩니다. 어쩌면 당신은 어떤 종류의 스마트 포인터를 찾고 있습니까? (부스트 스마트 포인터와 비슷합니다.) – Corbin

+0

@Xeo 예,하지만 유형 중 하나는 enums (정적)이고 다른 유형은 Things (동적)에 대한 포인터가됩니다. 구조가 이미 존재하며 템플릿으로 변환해도 작동 중입니다 – gardian06

답변

4

개체 유형에 따라 노드를 특수화하고 포인터 전문화의 경우 노드가 관리하는 포인터를 올바르게 할당하고 삭제하는 노드 유형의 소멸자를 만들 수 있습니다. 예를 들어

: 그런 다음 linked_list_node 형식의 인스턴스를 만들 때 올바른 템플릿 인수를 전달하여 다른 버전을 인스턴스화 할 수

//general node type for non-pointer types 
template<typename T> 
struct linked_list_node 
{ 
    T data; 
    linked_list_node<T>* next; 

    linked_list_node(const T& d): data(d), next(NULL) {} 
    ~linked_list_node() {} 
}; 

//specialized version for pointer types 
template<typename T> 
struct linked_list_node<T*> 
{ 
    typedef void (*deleter)(T*); 

    T* data; 
    linked_list_node<T>* next; 
    deleter d_func; //custom function for reclaiming pointer-type 

    linked_list_node(const T& d): data(new T(d)), next(NULL), d_func(NULL) {} 

    linked_list_node(const T& d, deleter func): data(new T(d)), 
               next(NULL), d_func(func) {} 
    ~linked_list_node() 
    { 
     if(d_func) 
      d_func(data); //execute custom function for reclaiming pointer-type 
     else 
      delete data; 
    } 
}; 

. 예를 들어

linked_list_node<MyPtr*> node(FooPtr); //creates the specialized ptr version 
linked_list_node<MyEnum> node(FooEnum); //creates a non-ptr version of the node 
+0

그런 다음 어떤 종류의 케이스 스위치를 사용하여 어느 것을 사용해야하는지 결정하십시오. – gardian06

+0

아니요, 단순히 포인터 유형 또는 열거 유형으로 템플릿 인수를 인스턴스화하십시오. 예를 들어,'linked_list_node '또는'linked_list_node '와 같이 말입니다. – Jason

+2

그러나 전체 목록 데이터 구조를 전문화하지 마십시오. 대신, 요소를 해제 할 때 목록에서 호출하는 도우미 함수 (또는 클래스)를 작성하면 도우미가 유형별로 특수화됩니다. 또한 특정 유형을 전문으로 할 수도 있습니다. 즉'FILE *'은'delete' 대신'fclose'를 호출 할 수 있습니다. –

1

템플릿 전문화는 최상의 대답이며 노드 유형을 혼합하지 않는 한 잘 작동합니다. 그러나 링크 된 노드의 유형을 혼합하려는 경우이를 수행하는 방법을 보여줍니다. 첫째, 간단한 템플릿 솔루션이 없습니다. 엄격한 유형 제한 때문에 링크 된 노드를 함께 입력해야합니다.

아주 일반적인 해결책은 variant 클래스를 구성하는 것입니다 (variant 유형으로 하나의 값을 보유 할 수 있으며 항상 어느 것이지 알고 있습니다). Qt는 예를 들어 QVariant 클래스입니다. 부스트는 boost::any입니다.

다음은 모든 유형을 보유 할 수있는 맞춤 변형 클래스를 사용하는 완전한 구현 예입니다. 나는 당신이 제안한 객체 포인터와 열거 형을 처리 할 수 ​​있지만 더 많이 보유하기 위해 확장 될 수있다. 인쇄 번 "OBJ 삭제"합니다

예 :

#include <iostream>                                                  

    int                                                      
    main(int argc, char **argv)                                                
    {                                                       
     LinkedList<VariantExample> elementObj(new ExampleObj);                                         

     LinkedList<VariantExample> elementEnum(enumOne);                                          

     elementEnum.setNext(elementObj);                                              
    } 

// VariantExample class. Have a look at [QVariant][4] to see how a fairly 
// complete interface could look like. 

     struct ExampleObj                                                   
     {                                                       
     };                                                      

     enum ExampleEnum                                                   
     {                                                       
      enumOne,                                                    
      enumTwo                                                    
     };                                                      

     struct VariantExample                                                  
     {                                                       
      ExampleObj* obj;  // or better boost::shared_ptr<ExampleObj> obj                                                  
      ExampleEnum en;                                                   

      bool is_obj;                                                   
      bool is_enum;                                                   

      VariantExample() : obj(0), is_obj(false), is_enum(false) {} 

      // implicit conversion constructors 

      VariantExample(ExampleObj* obj_) : is_obj(true), is_enum(false)                                     
      { obj = obj_;                                                   
      }                                                      

      VariantExample(ExampleEnum en_) : obj(0), is_obj(false), is_enum(true)                                       
      { en = en_;                                                    
      }                                                      

      // Not needed when using boost::shared_ptr above 

      void                                                     
      destroy()                                                    
      {                                                      
      if(is_obj && obj)                                                   
       {                                                     
       std::cout << "delete obj" << std::endl;                                           

       delete obj;                                                  
       }                                                     
      }                                                      

     };    


// The linked list template class which handles variant classes with a destroy() 
// method (see VariantExample). 

    template                                                     
    <                                                       
     typename _type_ = VariantExample                                                  
    >                                                       
    struct LinkedList                                                   
    {                                                       
     LinkedList* m_next;                                                  

     _type_ m_variant;                                                  

     explicit                                                    
     LinkedList(_type_ variant_) : m_next(0), m_variant(variant_){ }                                        

     void                                                     
     setNext(LinkedList& next_){ m_next = &next_; }                                          

     // Not needed when using boost::shared_ptr above 

     ~LinkedList()                                                   
     {                                                      
     m_variant.destroy();                                                 
     }                                                      
    };                                                       

을 elementObj의 파괴 방법은 한 번 LinkedList의의 소멸자가 호출 될 때 호출하기 때문에, 출력은 한 번만 나타나고있다 "obj가 삭제". 다시 말하지만, 삭제/소유권에 대해 구체적으로 설명 했으므로이 예제에는 destroy 메소드/인터페이스가 있습니다. LinkedList 클래스의 소멸자에서 명시 적으로 호출됩니다. 즉, 더 나은 소유권 모델을 구현할 수 있습니다. boost::shared_ptr. 그렇다면 수동으로 파괴 할 필요가 없습니다. 그것은 conversion constructors에 대해 읽는 것을 돕습니다.

// the first parameter becomes boost::shared_ptr<ExampleObj>(new ExampleObj)) 
    // and is deleted when LinkedList is destroyed. See code comments above. 

    LinkedList<> elementObj(new ExampleObj);                                         

마지막으로 LinkedList 체인에 나타날 수있는 모든 유형을 보유하려면 하나의 변형 클래스가 있어야합니다. 두 개의 서로 다른 LinkedList Variant 유형은 "next"포인터 유형 때문에 다시 작동하지 않습니다. 호환되지 않을 것입니다.

각주 : 유형 제약은 쉬운 해결책을 어떻게 방지합니까?링크 된 노드 "next"포인터 유형이 베어 메탈 템플리트 이름, 바로 가기가 아니라 템플릿 인수를 포함하여 실제로 자격이 있는지를 상상해보십시오. 컴파일러가 유형 컴플렉스를 판별하는 데 사용되는 유형 기호로 끝납니다.

+0

노드의 다른 유형으로 node.next를 설정하자마자 Jason의 예제가 컴파일되지 않아야합니다. – muenalan

+0

템플릿을 사용하면 아이디어가 형식 제약 조건을 적용하는 것이므로 ... 컴파일하지 않는 것이 오류가 아니라 의미합니다 타입 제약 규칙을 깨뜨린 것입니다. 이것은 실행 시간보다는 컴파일시에 경고하는 것이 훨씬 낫습니다. – Jason

+0

그래, 합의 : 아무 템플릿 넌센스는 런타임에 몰래합니다;) 그래서, 내 요점 : 이완 타입 제한에 대한 변종. 그러나 템플릿을 사용하는 아이디어는 언어 제약을 따르지 않고 코드 중복을 방지하는 것입니다. 유형 제한을 포함하여. 답에 대한 Ben Voigts의 코멘트를 참조하십시오. – muenalan

관련 문제