Эффективное использования STL vector-а
Использование STL контейнера vector. Производительность vector-а
Использование контейнеров стандартной библиотеки C++, всегда обусловлено простотой и удобством, производительностью. Но как и всякий "инструмент" его нужно использовать правильно, ведь хороший и эффективный инструмент в неумелых руках может быть бесполезен или неэффективен. В этой небольшой статье, я поведаю, как его использовать максимально эфективно и какие проблемы, подводные камни могут возникнут при первом знакомстве.
[spoiler]
Начнем пожалуй с самого истока
STL - стандартаная библиотека шаблонов. То есть, все то, что в стандартной библиотеке выражено шаблоном(ами), и есть STL. Но по большей части STL-ем принято считать именно контейнеры, алгоритмы и итераторы.
STL уже давно вошла в стандартную библиотеку C++, но все же не все пользуются ей в полной мере во основном из-за незнания о существовании тех или иных шаблонных классов.
И так вернемся конкретно к вектору.
Контейнер vector - это то же массив, который может содержать в себе любой встроенный или пользовательский тип. Но по сравнению со встроенным массивом у него есть ряд преимуществ.
- Он сам знает свой размер, (метод size())
- Можно легко менять размер(добавлять, удалять элементы), во время выполнения
- При удалении, очистки он вызывает деструкторы классов(ну это преимущество спорно=))
Пробежимся по основным .
Пора увидеть его в действии!
При переборе вектора через итераторы, нужно приучить себя писать преинкремент(++it), так он эфективнее.
Создание статического вектора:
Самый частый случай, проблем с созданием статического вектора - создание его в классе.
Чтобы создать в классе статический вектор, нужно его описать в .h и определить в .cpp. В данном случаи я поместил все в один файл, только ради простоты. Так можно создавать не только статический вектор, но и любой другой статический контейнер.
Теперь об эффективности
Вектор эффективен, в случаях если Вам нужен контейнер, в которые вы будете накапливать элементы. То есть - добавлять. Вектор эффективен при добавлении в конец методом push_back(), и при удалении с конца pop_back().
При вставке или удалении в произвольном месте (методы insert() и erase()), эффективность вектора хуже в сравнении со списком(list) или двусторонней очередью(deque). Связанно это с тем что, вектор хранит данные в памяти последовательно, что дает быстрый произвольный доступ и возможность использовать вектор, как обычный массив. К примеру в те же функции OpenGL вместо указателя на C массив, можно указать &имя_вектора.
У вектора есть не только размер(size()), но и емкость(capacity()), емкость это максимальное количество элементов которые при добавлении не вызовет переспраделении внутреннего буфера. При превышении этого значения вектор выделяет новый внутренней буфер(allocator), и копирует все элементы из старого буфера в новый, удаляя при этом из старого. То, есть если мы храним в нем большие объекты классов, то это операция будет довольно дорогостоящая. Особенно остро это "почувствуется" на больших объектах со сложным деструктором.
Емкость задана самой реализацией стандартной библиотеки.
Если же хранит в векторе указатели на объекты, то это очень повышает эффективность хранения в векторе, особенно больших объектов.
Хранить не большие объекты или встроенные типы в векторе, довольно эффективно.
Вывод
Если вы не собираетесь часто удалять элементы контейнера, и Вам не нужно вставлять элементы в начало и середину. И Вы собираетесь хранить не большие объекты, встроенные типы, или указатели на любые объекты(большие или не очень=)). То лучше предпочесть вектор, и помнить какие операции с ним, что делают, внутри него, в том числе. И какие из них будут не слишком дорогостоящие.
Использование контейнеров стандартной библиотеки C++, всегда обусловлено простотой и удобством, производительностью. Но как и всякий "инструмент" его нужно использовать правильно, ведь хороший и эффективный инструмент в неумелых руках может быть бесполезен или неэффективен. В этой небольшой статье, я поведаю, как его использовать максимально эфективно и какие проблемы, подводные камни могут возникнут при первом знакомстве.
[spoiler]
Начнем пожалуй с самого истока
STL - стандартаная библиотека шаблонов. То есть, все то, что в стандартной библиотеке выражено шаблоном(ами), и есть STL. Но по большей части STL-ем принято считать именно контейнеры, алгоритмы и итераторы.
STL уже давно вошла в стандартную библиотеку C++, но все же не все пользуются ей в полной мере во основном из-за незнания о существовании тех или иных шаблонных классов.
И так вернемся конкретно к вектору.
Контейнер vector - это то же массив, который может содержать в себе любой встроенный или пользовательский тип. Но по сравнению со встроенным массивом у него есть ряд преимуществ.
- Он сам знает свой размер, (метод size())
- Можно легко менять размер(добавлять, удалять элементы), во время выполнения
- При удалении, очистки он вызывает деструкторы классов(ну это преимущество спорно=))
Пробежимся по основным .
- push_back(element) - добавить элемент в конец vector-а
pop_back(element) - удалить последний элемент vector-а
insert(***) - три варианта(перезагрузки метода) вставки в какую либо область в векторе, первый параметр позиция вставки заданная итераторам, остальные указывают на контейнер, или количество и контейнер, или пару итераторов указывающих от какой до какой позиции из другого контейнера взять данные.
erase(iterator или iterator от, и до) - удаляет элемент или последовательность элементов из vector-а
begin() - возвращает итератор, указывающий на начало коллекции.
end() - возвращает итератор, указывающий на конец коллекции. При этом он указывает не самый последний элемент, а на воображаемый элемент за последним.
at(index) - метод доступа, к элементам коллекции, в отличии от оператора [], проверяет выход из-за границ коллекции, и в случаи чего генерит исключение.
clear() - удаляет все элементы коллекции, при этом если в нем содержаться объекты классов вызывает их деструкторы. А если же указатели на объекты, то у Вас будет утечка памяти(memory leaks=)), так delete за Вас никто не вызовет.
Пора увидеть его в действии!
|
При переборе вектора через итераторы, нужно приучить себя писать преинкремент(++it), так он эфективнее.
Создание статического вектора:
Самый частый случай, проблем с созданием статического вектора - создание его в классе.
Чтобы создать в классе статический вектор, нужно его описать в .h и определить в .cpp. В данном случаи я поместил все в один файл, только ради простоты. Так можно создавать не только статический вектор, но и любой другой статический контейнер.
|
Теперь об эффективности
Вектор эффективен, в случаях если Вам нужен контейнер, в которые вы будете накапливать элементы. То есть - добавлять. Вектор эффективен при добавлении в конец методом push_back(), и при удалении с конца pop_back().
При вставке или удалении в произвольном месте (методы insert() и erase()), эффективность вектора хуже в сравнении со списком(list) или двусторонней очередью(deque). Связанно это с тем что, вектор хранит данные в памяти последовательно, что дает быстрый произвольный доступ и возможность использовать вектор, как обычный массив. К примеру в те же функции OpenGL вместо указателя на C массив, можно указать &имя_вектора.
У вектора есть не только размер(size()), но и емкость(capacity()), емкость это максимальное количество элементов которые при добавлении не вызовет переспраделении внутреннего буфера. При превышении этого значения вектор выделяет новый внутренней буфер(allocator), и копирует все элементы из старого буфера в новый, удаляя при этом из старого. То, есть если мы храним в нем большие объекты классов, то это операция будет довольно дорогостоящая. Особенно остро это "почувствуется" на больших объектах со сложным деструктором.
Емкость задана самой реализацией стандартной библиотеки.
|
Если же хранит в векторе указатели на объекты, то это очень повышает эффективность хранения в векторе, особенно больших объектов.
Хранить не большие объекты или встроенные типы в векторе, довольно эффективно.
Вывод
Если вы не собираетесь часто удалять элементы контейнера, и Вам не нужно вставлять элементы в начало и середину. И Вы собираетесь хранить не большие объекты, встроенные типы, или указатели на любые объекты(большие или не очень=)). То лучше предпочесть вектор, и помнить какие операции с ним, что делают, внутри него, в том числе. И какие из них будут не слишком дорогостоящие.
7651
20.07.2012



.