Расширение std :: list

Мне нужно использовать списки для моей программы, и мне нужно было решить, использовать ли я std :: vector или std :: list. Проблема с вектором заключается в том, что нет метода удаления, а в списке нет оператора []. Поэтому я решил написать свой собственный класс, расширяющий std :: list и перегружающий оператор [].

Мой код выглядит так:

#include <list>

template <class T >
class myList : public std::list<T>
{
public:
T operator[](int index);
T operator[](int & index);
myList(void);
~myList(void);
};

#include "myList.h"

template<class T>
myList<T>::myList(void): std::list<T>() {}

template<class T>
myList<T>::~myList(void)
{
std::list<T>::~list();
}

template<class T>
T myList<T>::operator[](int index) {
int count = 0;
std::list<T>::iterator itr = this->begin();
while(count != index)itr++;
return *itr;    
}

template<class T>
T myList<T>::operator[](int & index) {
int count = 0;
std::list<T>::iterator itr = this->begin();
while(count != index)itr++;
return *itr;
}

Я могу скомпилировать его, но получаю ошибку компоновщика, если пытаюсь его использовать. Любые идеи?

14.12.2008 11:30:16
У вас есть T operator[](int index);и, T operator[](int & index);но вы можете использовать T& operator[](int index)и const T& operator[](int index) constвместо. Кроме того, внутри этих функций вы можете выполнять while (index--)вместо создания новой переменной для отслеживания количества.
Dennis 13.08.2013 22:17:42
8 ОТВЕТОВ
РЕШЕНИЕ

Весь код шаблона должен быть помещен в заголовочный файл. Это заполнить исправить проблемы с связью (это самый простой способ). Это происходит потому, что компиляторы компилируют каждый исходный файл (.cc) отдельно от других файлов. С другой стороны, ему нужно знать, какой именно код ему нужно создать (т. Е. Чем заменяется T в шаблоне), и у него нет другого способа узнать это, если программист не скажет это явно или не включит весь код, когда шаблон инстанцирование происходит. Т.е. когда компилируется mylist.cc, он ничего не знает о пользователях mylist и о том, какой код нужно создать. С другой стороны, если listuser.cc скомпилирован и присутствует весь код mylist, компилятор создает необходимый код mylist. Вы можете прочитать больше об этом здесь или в Страуструпе.

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

Кроме того, я не знаю, как вы планируете его использовать, но ваш оператор [] имеет время O (N), что, вероятно, легко приведет к циклам O (N * N) ...

10
14.12.2008 11:51:34
«ваш оператор [] имеет время O (N)» - именно поэтому он не включен в стандарт std::list<>.
Michael Burr 14.12.2008 17:29:49

Векторы имеют метод стирания, который может удалять элементы. Это не достаточно?

6
14.12.2008 11:34:13
Его не так просто использовать, как метод удаления в std :: list
Alexander Stolz 14.12.2008 11:38:12
Тогда используйте вместо этого std :: remove?
Jasper Bekkers 14.12.2008 12:42:48
Не знал об этом. Я посмотрю на это
Alexander Stolz 14.12.2008 15:20:48
@blizzarac: Почему это не так просто? Разве myvec.erase (myvec.begin () + index) не достаточно легок (индекс - это просто size_t!)?
mmmmmmmm 28.01.2009 18:32:35

Вы должны переместить весь код вашего шаблона в заголовок.

1
14.12.2008 11:34:16

Учитывая ваше оригинальное постановка проблемы,

Мне нужно использовать списки для моей программы, и мне нужно было решить, использовать ли я std :: vector или std :: list. Проблема с вектором заключается в том, что нет метода удаления, а в списке нет оператора [].

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

Вы все еще можете достичь того, что вы хотите, используя std::vectorи std::removeфункцию. Если vэто std::vector<T>, то чтобы удалить значение value, вы можете просто написать:

#include <vector>
#include <algorithm>
T value = ...; // whatever
v.erase(std::remove(v.begin(), v.end(), value), v.end());
21
14.12.2008 12:55:23
Это должно быть: v.erase (std :: remove (v.begin (), v.end (), value), vec.end ());
dalle 14.12.2008 12:55:37
И версия с одним элементом: v.erase (std :: find (...));
Martin York 14.12.2008 13:17:42
Если вы знаете индекс элемента, который хотите стереть, например, v [3], вы также можете использовать v.erase (v.begin () + 3). Итераторы произвольного доступа и все такое ...
Mr.Ree 15.12.2008 09:44:28

Очевидный материал уже был подробно описан:

Но методы, которые вы выбираете для реализации ??

  • Destructor.
    • Не обязательный компилятор сгенерирует это для вас.
  • Две разные версии оператора [] бессмысленны
    • Также вы должны быть uisng std :: list :: size_type в качестве индекса
    • Если вы не собираетесь поддерживать отрицательные индексы.
  • Константных версий оператора нет []
  • Если вы собираетесь реализовать [], вы также должны сделать в ()
  • Вы пропустили все разные способы построения списка.
  • Контейнеры должны определять несколько типов внутри
1
15.12.2008 07:57:03

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

5
15.12.2008 00:42:38

Нет необходимости вызывать деструктор std :: list, потому что вы уже наследуете от std :: list, когда деструктор вызывается для myList автоматически, вызывается деструктор std :: list.

0
14.12.2008 15:03:46
Отсутствие виртуального деструктора было бы проблемой только в том случае, если бы он попытался удалить объект myList через указатель на std :: list, что в любом случае было бы действительно странным использованием контейнера.
Nemanja Trifunovic 14.12.2008 15:47:58

В зависимости от ваших потребностей, вы должны использовать std::vector(если вам нужно часто добавлять / удалять в конце и произвольный доступ), или std::deque(если вам нужно часто добавлять / удалять в конце или в начале, и ваш набор данных огромен, и до сих пор хочу произвольный доступ). Вот хорошая картина, показывающая, как принять решение:

Выбор контейнера
(источник: adrinael.net )

53
23.02.2019 05:00:15
Это здорово, особенно если вы нашли время, чтобы сделать это! +1
Samaursa 31.10.2011 02:43:48