определение, является ли шаблонный тип динамическим - PullRequest
1 голос
/ 07 марта 2012

Я пишу шаблон рабочего класса, и это может быть просто глупый вопрос, но если у меня есть структура шаблона (связанный список) для хранения, возможно, указателей на объекты, то как я узнаю, что они удаляются, или что они где указатели на первом месте?

например: связанный список будет использоваться в этой программе двумя способами

указатель на объект класса Thing размещается внутри узла внутри связного списка

перечисление размещается внутри узла внутри связного списка

Я знаю, что узлы удаляются, но как мне узнать, что вещь в узле - это указатель, так что он также может быть удален, а не просто является объектом с нулевой ссылкой?

Ответы [ 2 ]

4 голосов
/ 07 марта 2012

Вы можете специализировать узел на основе типа объекта, а для специализации указателя создать деструктор для типа узла, который правильно выделяет и удаляет указатель, управляемый узлом.

Например:

//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 голос
/ 08 марта 2012

Специализация шаблона - лучший ответ, и он будет работать хорошо, если вы не смешиваете типы узлов. Однако, если вы хотите смешать типы связанных узлов, позвольте мне показать вам, как это сделать. Во-первых, не существует простого шаблонного решения. Из-за строгих ограничений на типы вам придется печатать ваши связанные узлы вместе.

Довольно распространенным решением является создание класса вариантов (который может содержать одно значение с типами вариантов и всегда знает, какой из них). Например, у Qt есть класс QVariant . Boost имеет boost :: any .

Вот полный пример реализации с использованием пользовательского класса вариантов, который может содержать любой из ваших типов. Я могу обработать предложенный вами указатель объекта и перечисление, но может быть расширен для большего хранения

Пример, который напечатает «delete 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();                                                                                                                                                                                                 
      }                                                                                                                                                                                                                      
    };                                                                                                                                                                                                                          

Поскольку метод destroy для elementObj вызывается один раз, когда вызывается деструктор LinkedList, вывод «delete obj» появляется только один раз. Опять же, поскольку вы были достаточно конкретны в отношении удаления / владения, в этом примере есть метод / интерфейс уничтожения. Он будет явно вызван в деструкторе класса LinkedList. Лучшая модель собственности может быть реализована с помощью т.е. повышение :: shared_ptr . Тогда вам не нужно уничтожать его вручную. Кстати, помогает прочитать о конструкторах преобразования .

  // 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 не будут работать, опять же, наконец, из-за «следующего» типа указателя; который был бы не совместим.

Сноска: Как ограничения типа мешают простому решению? Представьте, что указатель типа «следующий» для связанного узла - это не просто пустое имя шаблона, это ярлык, но на самом деле он квалифицирован, включая аргументы шаблона - что в итоге становится символом типа, который компилятор использует для оценки совместимости типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...