Расширение std :: list - PullRequest
       34

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

6 голосов
/ 14 декабря 2008

Мне нужно использовать списки для моей программы, и мне нужно было решить, использовать ли я 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;
}

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

Ответы [ 8 ]

53 голосов
/ 14 декабря 2008

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

Container Choice
(источник: adrinael.net )

21 голосов
/ 14 декабря 2008

Исходя из вашей первоначальной постановки задачи,

Мне нужно использовать списки для моей программы, и мне нужно было решить, использовать ли я 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());
10 голосов
/ 14 декабря 2008

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

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

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

6 голосов
/ 14 декабря 2008

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

5 голосов
/ 14 декабря 2008

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

1 голос
/ 14 декабря 2008

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

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

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

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

0 голосов
/ 14 декабря 2008

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

...