Также vector предоставляет безопасность, которой просто невозможно достичь в случае обычных массивов. В отличие от массивов vector с помощью метода at предлагает проверку диапазонов. Если в at передается неправильный индекс, он выбрасывает исключение out_of_range, которое затем можно перехватить с помощью catch и адекватно на него отреагировать. Например:
try {
intVec.at(300) = 2;
} catch(std::out_of_range& e) {
std::cerr << "out_of_range: " << e.what() << std::endl;
}
Как вы знаете, если обратиться к элементу за пределами массива с помощью operator[], оператор сделает то, что ему сказано сделать, и вернет то, что находится в указанной области памяти. Это плохо, так как либо программа обрушится в результате попытки доступа к области памяти, к которой она доступа не имеет, либо она молча изменит содержимое области памяти, принадлежащей другому объекту кучи, что обычно еще хуже. operator[] для vector работает точно так же, но когда требуется обезопасить код, используйте at.
Итак, вот краткий курс по vector. Но что vector? Если вы используете С++, то вас, вероятно, волнуют проблемы производительности, и вам не понравится, если вам просто дадут что-то и скажут, что это работает. Вполне справедливо. За обсуждением работы vector и советами по его эффективному использованию обратитесь к рецепту 6.2.
Рецепт 6.2.
6.2. Эффективное использование vector
Вы используете vector, и при этом имеются жесткие требования по объему или времени выполнения кода и требуется снизить или устранить все накладные расходы.
Поймите, как реализован vector, узнайте о сложности методов вставки и удаления и минимизируйте ненужные операции с памятью с помощью метода reserve. Пример 6.2 показывает некоторые из этих методик в действии.
#include
#include
#include
using std::vector;
using std::string;
void f(vector
// Передача vec по ссылке (или,
// если требуется, через указатель)
// ...
}
int main() {
vector
// планируется поместить определенное количество
// объектов
vector
// Заполняем vec...
f(vec);
vec2 reserve(500); // Или постфактум говорим vector,
// что требуется буфер достаточно большого
// размера для хранения объектов
// Заполняем vec2...
}
Ключ к эффективному использованию vector лежит в знании его работы. Когда у вас есть четкое представление реализации vector, вопросы производительности становятся очевидными.
vector — это по сути управляемый массив. Более конкретно, vector — это непрерывный фрагмент памяти (т.е. массив), который достаточно велик для хранения T, где vector от массива — это автоматическое управление памятью массива, методы для вставки и получения элементов и методы, которые предоставляют метаданные о контейнере, такие как размер (число элементов) и емкость (размер буфера), а также информацию о типе: vector — это тип T, vector — это тип указатель-на-T и т.д. Два последних и некоторые другие являются частью любого стандартного контейнера, и они позволяют писать обобщенный код, который работает независимо от типа T. Рисунок 6.1 показывает графическое представление того, что предоставляют некоторые из методов vector, если vector имеет размер 7 и емкость 10.
Рис. 6.1. Внутренности vector