确定模板类型是否是动态的

时间:2012-03-07 19:24:19

标签: c++ templates dynamic

我正在编写一个工作类的模板,这可能只是一个愚蠢的问题,但如果我有一个模板结构(链表)来保存可能指向对象的指针,那么我怎么知道它们被删除了,或者说他们在哪里指针?

例如:linkedList将在此程序中以2种方式使用

指向Thing类对象的指针放在linkedList

内的节点内

枚举被放置在linkedList

内的节点内

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

模板专业化是最好的答案,只要您不混合节点类型,它就会很好用。但是,如果要混合链接节点的类型,请告诉我如何操作。首先,没有直接的模板解决方案。由于严格的类型约束,您必须将链接节点类型转换为一起。

一个非常常见的解决方案是构造一个变体类(可以使用变量类型保存一个值,并始终知道哪个值)。例如,Qt有一个QVariant类。 Boost有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();                                                                                                                                                                                                 
      }                                                                                                                                                                                                                      
    };                                                                                                                                                                                                                          

因为在调用LinkedList的析构函数时elementObj的destroy方法调用了一次,所以输出“delete obj”只出现一次。同样,由于您对删除/所有权非常具体,因此该示例具有destroy方法/接口。它将在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类型不起作用;这是不兼容的。

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