2010-10-12 4 views
3

Я использую много векторов в моем программировании, и вообще пройти вектор для существующего значения я использую зЬй :: найти как в:станда :: найти против вывода шаблона из вектора

std::vector<int> foo; 
std::vector<int>::iterator pos(std::find(foo.begin(), foo.end(), bar); 

Это настоящая скука. Так что я пошел к получению шаблона из станд :: вектор для обеспечения найти метод:

template<class T> 
class foovector : public std::vector<T> 
{ 
public: 
    typename std::vector<T>::iterator find(const T& value) 
    { 
     return std::find(this->begin(), this->end(), value); 
    } 
}; 

И теперь я могу сделать ФАЙНД более естественно:

foovector<int> foo; 
foovector<int>::iterator pos(foo.find(bar)); 

Мой вопрос заключается в том, что это кажется естественным и очевидным расширением вектора, поэтому почему он не является частью STL или даже boost? Я чувствую, что мне не хватает какого-то Тайного Знания.

+3

Свободные функции предпочтительнее функций-членов. Это те знания, которые вам не хватает. О, и 'std :: vector * v = новый foovector ; delete v; // UB'. – GManNickG

+2

Почему это «очевидное расширение»? Это очевидно только в том случае, если вы предполагаете, что функции-члены предпочтительнее, чем функции, не являющиеся членами. Это в значительной степени статья веры в Java, но это не делает ее истиной *. В C++ функции, не являющиеся членами, обычно предпочтительны, когда это возможно, как говорит @GMan. (В частности, 'std :: find' является универсальным и многоразовым, он также работает на' std :: list' или 'std :: deque' или даже на вашем собственном самодельном контейнере. Функция-член не может повторно использовать в других типах контейнеров, так почему это должно быть предпочтительным?) – jalf

+1

Другим преимуществом версии, не являющейся членом, является то, что она работает на итераторах, а не на самом векторе. Я могу использовать его для поиска только в первых 10 элементах вектора: 'std :: find (foo.begin(), foo.begin() + 10)'. Вы также теряете эту способность в версии участника. – jalf

ответ

4

А что вы делаете то, что вы хотите достичь, и до сих пор не вдаваться в сомнительный путь наследования от станд :: вектор

определяют автономный функцию

template <typename T> 
typename std::vector<T>::const_iterator find(const std::vector<T>& v, const T& value) 
{ 
    return std::find(v.begin(), v.end(), value); 
} 

вы можете поместить это в патезрасе (что, технически говоря, недопустимо) или в каком-то другом пространстве имен (с компромиссом, который он не найдет ADL, поэтому вам нужно будет его квалифицировать). HTH

P.S. кстати можно обобщить это для всех контейнеров

template <typename Container, typename T> 
typename Container::const_iterator find(const Container& c, const T& value) 
{ 
    return std::find(c.begin(), c.end(), value); 
} 
+1

Желательно, чтобы все алгоритмы в стандарте имели этот интерфейс ... – Inverse

+2

@ Inverse: Мы хотим использовать алгоритмы на основе диапазона. См. «Итераторы должны пройти» Александреску и Boost.Range. – GManNickG

+1

Разве это не должно быть 'const_iterator'? –

1

Потому что, если вам обычно нужно делать много находок, вы должны использовать набор или карту (или хешированную версию). Мало того, что это проще написать, но они имеют сложность, а unsorted vector - O(n).

С картой:

map<stuff> m 
m[bar] // returns a reference to the element with key bar. 

Набор похож.

6
  1. Наследование от STL контейнеров not considered a great idea - они не имеют виртуальные деструкторы, так как они не были предназначены для этого.

  2. <vector> Сила - это не его возможность поиска - для этого есть другие контейнеры.

  3. Я подозреваю, что большинство людей просто не находят код, который вы заменяете назойливым.

+0

'' может выполнять более быстрый поиск, чем '', если он отсортирован.Одна из проблем заключается в том, что существует два вида поиска, и член, называемый 'find', будет немного неоднозначным. – Potatoswatter

+0

@Potatoswatter - согласовать поиск отсортированного вектора можно быстрее, но для больших и/или быстро изменяющихся наборов данных вы бы рекомендовали этот подход? Много перетасовки элементов, перераспределение памяти, ручная сортировка только для быстрого поиска. –

+0

Простой линейный сканирование несортированного вектора быстрее, чем что-либо еще, до 10 элементов. Измерьте это. Это интересно. –

5

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

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

+0

Стандарт должен быть как можно более общим, ценой небольшого количества подробностей. Вы всегда можете оптимизировать свой собственный общий вариант использования. –

2

Возможно, потому что вектор является самым простым типом контейнера, и лучше использовать (ассоциативные) контейнеры, если поиск является приоритетом.

Вектор имеет функцию O (1), если вы выполняете поиск по индексу, но если вы используете алгоритм поиска, вы теряете всю эту выгоду.

+1

+1, они не решались стандартизировать функции-члены контейнера, отличные от O (1). – Potatoswatter

+0

@Potatoswatter: Действительно? Я не знал этого, хотя это имеет смысл. –

+0

Ну, за исключением 'string', я полагаю, но это скорее совпадающий контейнер. – Potatoswatter

1

На самом деле, я завернут большинство бесплатных функций, определенных в <algorithm> с версиями с контейнерами/диапазонов вместо итераторов. Это не только намного безопаснее (я могу добавить простые проверки, убедиться, что диапазон действителен и т. Д.), Это также намного удобнее.

В вашем случае, общий способ сделать это:

template <typename Container> 
typename Container::iterator find(Container& c, 
            typename Container::value_type const& v) 
{ 
    return std::find(c.begin(), c.end(), v); 
} 

template <typename Container> 
typename Container::const_iterator find(Container const& c, 
             typename Container::value_type const& v) 
{ 
    return std::find(c.begin(), c.end(), v); 
} 

Это может быть использован с любым STL-совместимый контейнер.

Конечно, то, что было бы неплохо было бы адаптировать это с помощью концепции для того, чтобы использовать функцию члена find при наличии ...

Смежные вопросы