Вопрос по шаблонам C

#c #templates

#c #шаблоны

Вопрос:

 template <class T>
class ListNode {

public:
    T* data;
        ListNode<T>* next;
}
  

Допустим, у меня есть шаблон узла списка, и где-то в коде я хочу получить копию данных — имеется в виду не копия указателя на данные (T *), а новый указатель (T *), который будет указывать на другое место в памяти, содержащее там ту же информацию.

Как я могу это сделать при использовании шаблонов C ? Как я могу скопировать (* данные), если я не знаю, какой тип T.

Комментарии:

1. Как вы это делаете, когда знаете тип? Это работает идентично для типов шаблонов.

2. Вы знаете этот тип … T

3. @Konrad: Или это в равной степени не работает для не-шаблонов. Все ответы на данный момент вызывают нарезку.

Ответ №1:

Компилятор знает тип T . Чего он не знает, так это на сколько экземпляров T указано. С точки зрения получения практической реализации, коротким ответом было бы не использовать типы указателей. Вместо этого используйте контейнеры. Поскольку вы все равно копируете данные узла, накладные расходы минимальны. Явный пример ниже:

 template <class T>
class ListNode {
public:
    // use a vector as the  container
    std::vector<T> data;
    ListNode<T>* next;
    // initializer from pointer primitive
    ListNode(const T* ps,size_t elements)
    {
        data.assign(ps,ps elements);
    }
    // copy templated instance
    ListNode(const ListNodeamp; arg)
    {
        data = arg.data;
    }
    // assignment
    ListNodeamp; operator=(const ListNodeamp; arg)
    {
        if (this != amp;arg)
        {
            data = arg.data;
        }
        return *this;
    }
};
  

Фактическое использование было бы похоже на это:

 {
    const char* ps = "Hello World";
    ListNode<char> ln1(ps,strlen(ps));
    ListNode<char> ln2 = ln1;
}
  

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

Комментарии:

1. 1: несмотря на ограниченность примера, все еще простая альтернатива, и простота хороша.

Ответ №2:

T должен быть копируемым, чтобы вы могли делать

    template <class T>
   ListNode<T>::ListNode(const ListNode<T>amp; src)
   {

        ...
        // given a preexisting copy, src, create a new T to
        // perform a copy
        T* destT = new T(*srcT);
   }
  

Если у T есть конструктор копирования, это сработает. Если этого не произойдет, компилятор выдаст вам ошибку (вероятно, очень загадочную)

Комментарии:

1. NM … Это связано с кофе, и это не с вашей стороны.

2. почему компилятор должен выдавать ошибку; Не будет ли компилятор генерировать конструктор копирования по умолчанию?

Ответ №3:

Используйте operator= или конструктор копирования. Стандартной практикой является то, что оба из них будут создавать копию объекта.

Так, например:

 T *p = other_pointer;
*p = *data;
  

Или

 T* copy = new T(*data);
  

Комментарии:

1. Для значений «создать копию», которые допускают нарезку.

2. @Ben: Стандартной функции виртуального копирования не существует, поэтому вы берете то, что можете получить.

Ответ №4:

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

 template <class T>
class ListNode {
public:
    T* data;
    ListNode<T>* next;
    T* getCopy() { new T(*data); } // get copy of "data"
};
  

Предположим, вы используете это ListNode<T> для class A , тогда у вас может быть определен конструктор копирования для A (а также оператор присваивания):

 class A {
public:
  A(const Aamp; copy);
};
  

Теперь при вызове ListNode<T>::getCopy() он вызовет конструктор копирования A внутренне.

Комментарии:

1. -1: Потенциальная утечка памяти каждый раз, когда кто-то запрашивает копию, вероятно, не является хорошим дизайном… оберните это в интеллектуальный указатель или, предпочтительно, предоставьте явный конструктор копирования и / или оператор присваивания.

2. @AJG85, я не думаю, что это утечка памяти. Запрашивающий запрашивает копию T* , которая может храниться в data элементе другого объекта и может быть удалена в деструкторе.

3. Вы возвращаете копию следующим образом: T getCopy() const { *data; } то, что вы делаете, это выделяете память в куче и возвращаете указатель на нее в общедоступном методе, который может легко вызвать утечки памяти и потерянные указатели … тот, кто вызывает ваш метод, должен сохранить указатель и вызвать delete на нем, чтобы избежать утечки памяти без исключений.