2012-03-07 55 views
1

我写一个工人阶级的模板,这也可能只是一个愚蠢的问题,但如果我有一个模板结构(链表)到可能持有对象的指针,然后我怎么知道他们正在被删除,还是他们在哪里指针?确定模板类型是动态

例如:LinkedList的将在第2种方式使用在此程序

一个指针指向类的东西的物体被放置在节点内的链表

枚举被放置在节点内的内部内一个linkedList

我知道节点正在被删除,但我怎么知道节点中的东西是一个指针,以便它可以被删除,而不仅仅是一个空引用对象?

+0

您是否想制作不同类型的链接列表? – Xeo 2012-03-07 19:26:18

+0

为了确保我正确理解这一点,你想有一个LinkedList​​3210,然后能够推动Blah *进入它并让LinkedList自动销毁并释放链表的内容指向的所有对象?这似乎是班上不应该做的事情。如果你想保持一个对象存活,但是你已经将它推入列表并且该列表已被删除,该怎么办?也许你正在寻找某种智能指针? (像Boost智能指针。) – Corbin 2012-03-07 19:28:16

+0

@Xeo是的,但我的其中一种类型将枚举(静态),另一种类型将指向事物(动态)。结构已经存在,我正在努力,虽然现在将它转换为模板 – gardian06 2012-03-07 19:28:49

回答

4

您可以专注基于对象的类型的节点,并为指针专业化,创建节点型,妥善分配,并删除节点管理的指针析构函数。

例如:

//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类型的实例时传递正确的模板参数实例化不同的版本。例如,

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 2012-03-07 19:38:34

+0

不,只需使用指针类型或枚举类型实例化模板参数即可。例如,'linked_list_node ',或'linked_list_node '。 – Jason 2012-03-07 19:43:58

+2

但是不要专注于整个列表数据结构。相反,只需创建一个帮助器函数(或类),该函数在需要释放元素时调用,助手将按类型进行专门化。你也可以专门针对特定的类型,即'FILE *'可能会调用'fclose'而不是'delete'。 – 2012-03-07 19:49:24

1

模板专业化是最好的答案,并且将工作做好,只要你不混合类型的节点。但是,如果你想混合链接节点的类型,让我告诉你如何去做。首先,没有简单的模板解决方案。由于严格的类型限制,您必须一起键入您的链接节点。

甲相当普遍的解决方案是构建变体类(其可以容纳具有变化类型的一个值,并且总是知道哪一个)。例如,Qt有一个QVariant类。 Boost有boost::any

这是一个完整的示例实现,它使用可以容纳任何类型的自定义变体类。我可以处理你建议的对象指针和枚举,但可以扩展来保存更多。

这将打印“删除目标文件”一旦一个例子:

#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类的析构函数中显式调用。一个更好的所有权模式可以用ie来实现。 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类型将无法工作。这将不兼容。

脚注: 类型约束如何防止一个简单的解决方案吗?想象一下,链接节点的“下一个”指针类型不仅仅是裸模板名称,它是一个快捷方式,但实际上还包括模板参数 - 最终作为编译器用来判断类型兼容性的类型符号。

+0

只要你用不同类型的节点设置node.next,Jason的例子就不应该编译 – muenalan 2012-03-08 10:27:51

+0

带模板的想法是强制执行一个类型约束...所以它不会编译的事实不是错误,而是表示你已经打破了类型约束规则,这在编译而不是运行时要好得多。 – Jason 2012-03-08 14:26:16

+0

是的,同意:没有模板废话应潜入运行时;)所以,我的观点:宽松类型约束的变种。然而,使用模板的想法是为了防止代码重复而不违反语言限制;包括类型约束。见本Voigts评论你的答案。 – muenalan 2012-03-10 11:22:59