Перейти к содержимому

Как вернуть вектор из функции c

  • автор:

Возврат вектора из функции

Как правильно возвращать вектор из функции — возвращать сам вектор, указатель на него или итератор? «Правильность» интересует с точки зрения оптимального использования ресурсов и хорошего стиля программирования.

Отслеживать
371 1 1 золотой знак 5 5 серебряных знаков 13 13 бронзовых знаков
задан 2 апр 2014 в 17:10
DarkGenius DarkGenius
895 2 2 золотых знака 11 11 серебряных знаков 31 31 бронзовый знак
Передавайте в функцию ссылку на вектор, который вы собираетесь заполнять.
2 апр 2014 в 17:15
А если вектор хранится у меня как поле класса?
2 апр 2014 в 17:19
Темный гений, про RVO — правда
2 апр 2014 в 18:14
@mikillskegg, в данном случае (вектор является полем класса) это неправда.
2 апр 2014 в 19:03

@DarkGenius: Если время жизни вектора — не проблема, конечно возвращайте const ref. Основная проблема C++ и состоит, на мой взгляд, в том, что приходится чересчур много думать об аллокации/деструкции/копировании ресурсов и владении ими. Например, казалось бы, что опасного в конструкции v.push_back(v.back()); ?

5 апр 2014 в 14:30

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

Давайте-ка я суммирую дискуссию в комментариях здесь.

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

Затем, если вы уверены, что время жизни вектора, который вы передаёте, достаточно велико (например, вектор является полем класса), то вы можете возвращать ссылку на него. Внимание! При этом вы вводите потенциально опасную зависимость: если сам объект умрёт, ссылка на вектор тоже перестанет быт валидной! Сам объект не может знать, как его используют, и не является ли он, например, временным.

Затем, вы вполне можете вернуть вектор по значению, особенно если вы конструируете его на стеке в самой функции (и значит, не можете вернуть ссылку на него). Это кажется излишним копированием, но на самом деле оптимизатор часто может убрать ненужное копирование используя RVO/NRVO. (Вот ссылкf про это: NRVO in Visual C++ 2005). Тем не менее, иногда эта техника может всё же ведёт к копированию (например, потому, что оптимизатор не волшебник) и показывает плохие результаты.

И ещё: я бы не советовал возвращать итератор. Итераторы в C++ — ещё более хрупкая вещь, чем ссылки: любой чих в сторону вектора может его инвалидировать.

Класс vector

Класс вектора стандартной библиотеки C++ — это шаблон класса для контейнеров последовательности. Вектор хранит элементы заданного типа в линейном расположении и обеспечивает быстрый случайный доступ к любому элементу. Вектор — это предпочтительный контейнер для последовательности, если производительность случайного доступа находится в категории «Премиум».

Синтаксис

template > class vector 

Параметры

Type
Тип данных элементов, сохраняемых в векторе.

Allocator
Тип, представляющий сохраненный объект распределителя, содержащий сведения о распределении и отмене распределения памяти для вектора. Этот аргумент является необязательным, и значением по умолчанию является allocator .

Замечания

Для векторов время выполнения вставок и удалений элементов в конце последовательности является постоянной величиной. Время вставки и удаления элементов в середине вектора меняется линейно. Контейнер deque класса быстрее выполняется при вставке и удалении в начале и конце последовательности. Контейнер list класса быстрее выполняется при вставке и удалении в любом расположении в последовательности.

Расширение вектора происходит, когда функции-члену требуется увеличить последовательность в объекте вектора сверх его текущей емкости. Другие операции вставки и стирания могут изменять различные адреса хранения внутри последовательности. Во всех таких случаях итераторы или ссылки, указывающие на изменившиеся части последовательности, становятся недействительными. Если расширения не происходит, действительными остаются только итераторы и ссылки перед точкой вставки или удаления.

Ссылочный vector класс — это вложенный класс, объекты которого могут предоставлять ссылки на элементы (одиночные биты) в объекте vector .

Участники

Конструкторы

Имя Описание
vector Создает вектор определенного размера, вектор с элементами определенного значения, вектор с определенным allocator , или вектор как копию какого-либо другого вектора.

Определения типов

Имя Описание
[allocator_type] (#allocator_type) Тип, представляющий класс allocator для объекта вектора.
const_iterator Тип, предоставляющий итератор произвольного доступа, который может читать элемент const в векторе.
const_pointer Тип, предоставляющий указатель на элемент const в векторе.
const_reference Тип, предоставляющий ссылку на const элемент, хранящийся в векторе. Он используется для чтения и выполнения const операций.
const_reverse_iterator Тип, предоставляющий итератор произвольного доступа, который может читать любой элемент const в векторе.
difference_type Тип, представляющий различие между адресами двух элементов в векторе.
iterator Тип, предоставляющий итератор произвольного доступа, который может читать или изменять любой элемент в векторе.
pointer Тип, предоставляющий указатель на элемент в векторе.
reference Тип, предоставляющий ссылку на элемент, хранящийся в векторе.
reverse_iterator Тип, предоставляющий итератор произвольного доступа, который может читать или изменять любой элемент в обратном векторе.
size_type Тип, считающий количество элементов в векторе.
value_type Тип, представляющий тип данных, хранящихся в векторе.

Функции

Имя Описание
assign Удаляет вектор и копирует указанные элементы в пустой вектор.
at Возвращает ссылку на элемент в заданном положении в векторе.
back Возвращает ссылку на последний элемент вектора.
begin Возвращает итератор произвольного доступа, указывающий на первый элемент в векторе.
capacity Возвращает число элементов, которое вектор может содержать без выделения дополнительного пространства.
cbegin Возвращает постоянный итератор произвольного доступа, указывающий на первый элемент в векторе.
cend Возвращает константный итератор произвольного доступа, указывающий на позицию, следующую за концом вектора.
crbegin Возвращает константный итератор, который указывает на первый элемент в обратном векторе.
crend Возвращает константный итератор, который указывает на последний элемент в обратном векторе.
clear Очищает элементы вектора.
data Возвращает указатель на первый элемент в векторе.
emplace Вставляет элемент, созданный на месте, в указанное положение в векторе.
emplace_back Добавляет элемент, созданный на месте, в конец вектора.
empty Проверяет, пуст ли контейнер вектора.
end Возвращает итератор произвольного доступа, который указывает на конец вектора.
erase Удаляет элемент или диапазон элементов в векторе из заданных позиций.
front Возвращает ссылку на первый элемент в векторе.
get_allocator Возвращает объект классу allocator , используемому вектором.
insert Вставляет элемент или многие элементы в вектор по заданной позиции.
max_size Возвращает максимальную длину вектора.
pop_back Удаляет элемент в конце вектора.
push_back Добавляет элемент в конец вектора.
rbegin Возвращает итератор, указывающий на первый элемент в обратном векторе.
rend Возвращает итератор, который указывает на последний элемент в обратном векторе.
reserve Резервирует минимальную длину хранилища для объекта вектора.
resize Определяет новый размер вектора.
shrink_to_fit Удаляет лишнюю емкость.
size Возвращает количество элементов в векторе.
swap Меняет местами элементы двух векторов.

Операторы

Имя Описание
operator[] Возвращает ссылку на элемент вектора в указанной позиции.
operator= Заменяет элементы вектора копией другого вектора.

allocator_type

Тип, представляющий класс распределителя для объекта вектора.

typedef Allocator allocator_type; 

Замечания

allocator_type является синонимом для параметра-шаблона Allocator .

Пример

Пример использования см. в примере get_allocator allocator_type .

assign

Удаляет вектор и копирует указанные элементы в пустой вектор.

void assign(size_type count, const Type& value); void assign(initializer_list init_list); template void assign(InputIterator first, InputIterator last); 

Параметры

first
Положение первого элемента в диапазоне копируемых элементов.

last
Положение первого элемента за пределами диапазона копируемых элементов.

count
Количество копий элемента, вставляемых в вектор.

value
Значение элемента, вставляемого в вектор.

init_list
Объект initializer_list, содержащий вставляемые элементы.

Замечания

Во-первых, assign удаляет все существующие элементы в векторе. assign Затем либо вставляет указанный диапазон элементов из исходного вектора в вектор, либо вставляет копии нового указанного элемента значения в вектор.

Пример

/ vector_assign.cpp // compile with: /EHsc #include #include int main() < using namespace std; vectorv1, v2, v3; v1.push_back(10); v1.push_back(20); v1.push_back(30); v1.push_back(40); v1.push_back(50); cout cout cout cout ); for (auto& v : v3) < cout cout

at

Возвращает ссылку на элемент в заданном положении в векторе.

reference at(size_type position); const_reference at(size_type position) const; 

Параметры

position
Номер нижнего индекса или позиции элемента, на который включается ссылка в векторе.

Возвращаемое значение

Ссылка на элемент, индекс которого указан в аргументе. Если position размер вектора больше размера, at создается исключение.

Замечания

Если возвращаемое значение at назначено объекту const_reference , объект вектора не может быть изменен. Если возвращаемое значение at присвоено reference , то объект вектора можно изменить.

Пример

// vector_at.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 10 ); v1.push_back( 20 ); const int &i = v1.at( 0 ); int &j = v1.at( 1 ); cout
The first element is 10 The second element is 20 

back

Возвращает ссылку на последний элемент вектора.

reference back(); const_reference back() const; 

Возвращаемое значение

Последний элемент вектора. Если вектор пуст, возвращаемое значение не определено.

Замечания

Если возвращаемое значение back назначено объекту const_reference , объект вектора не может быть изменен. Если возвращаемое значение back присвоено reference , то объект вектора можно изменить.

При компиляции с помощью _ITERATOR_DEBUG_LEVEL 1 или 2 ошибка среды выполнения возникает при попытке доступа к элементу в пустом векторе. Дополнительные сведения см. в разделе "Проверенные итераторы".

Пример

// vector_back.cpp // compile with: /EHsc #include #include int main() < using namespace std; vector v1; v1.push_back( 10 ); v1.push_back( 11 ); int& i = v1.back( ); const int& ii = v1.front( ); cout

begin

Возвращает итератор произвольного доступа, указывающий на первый элемент в векторе.

const_iterator begin() const; iterator begin(); 

Возвращаемое значение

Итератор произвольного доступа, который указывает на первый элемент в vector или на элемент, следующий за пустым vector . Всегда сравнивайте возвращаемое значение, vector::end чтобы убедиться, что он действителен.

Замечания

Если возвращаемое значение begin назначено объекту vector::const_iterator , vector объект нельзя изменить. Если возвращаемое значение begin назначено объекту vector::iterator , vector объект можно изменить.

Пример

// vector_begin.cpp // compile with: /EHsc #include #include int main() < using namespace std; vectorc1; vector::iterator c1_Iter; vector::const_iterator c1_cIter; c1.push_back(1); c1.push_back(2); cout cout cout 
The vector c1 contains elements: 1 2 The vector c1 now contains elements: 20 2 

capacity

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

size_type capacity() const; 

Возвращаемое значение

Текущая длина хранилища, выделенного вектору.

Замечания

Функция-член resize будет более эффективной при выделении достаточной памяти для ее размещения. Используйте функцию-член reserve , чтобы указать объем выделенной памяти.

Пример

// vector_capacity.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 1 ); cout
The length of storage allocated is 1. The length of storage allocated is now 2. 

cbegin

Возвращает итератор const , направленный на первый элемент в диапазоне.

const_iterator cbegin() const; 

Возвращаемое значение

Итератор случайного доступа const , который указывает на первый элемент диапазона или расположение прямо за концом пустого диапазона ( cbegin() == cend() для пустого диапазона).

Замечания

При возвращаемом значении cbegin элементы в диапазоне не могут быть изменены.

Эту функцию-член можно использовать вместо функции-члена begin() , чтобы гарантировать, что возвращаемое значение будет const_iterator . Как правило, он используется с ключевое слово вычета auto типов, как показано в следующем примере. В примере Container следует рассматривать как изменяемый (не- const ) контейнер любого вида, который поддерживает begin() и cbegin() .

auto i1 = Container.begin(); // i1 is Container::iterator auto i2 = Container.cbegin(); // i2 is Container::const_iterator 

cend

Возвращает итератор, указывающий const на элемент после последнего элемента вектора.

const_iterator cend() const; 

Возвращаемое значение

Итератор const последнего итератора для вектора. Он указывает на элемент после последнего элемента вектора. Этот элемент является заполнителем и не должен быть разоменован. Используйте его только для сравнения. Если вектор пуст, то vector::cend() == vector::cbegin() .

Замечания

cend используется для проверки того, прошел ли итератор конец диапазона.

Эту функцию-член можно использовать вместо функции-члена end() , чтобы гарантировать, что возвращаемое значение будет const_iterator . Как правило, он используется с ключевое слово вычета auto типов, как показано в следующем примере. В примере Container следует рассматривать как изменяемый (не- const ) контейнер любого вида, который поддерживает end() и cend() .

auto i1 = Container.end(); // i1 is Container::iterator auto i2 = Container.cend(); // i2 is Container::const_iterator 

Возвращаемое cend значение не должно быть разоменовывано. Используйте его только для сравнения.

clear

Очищает элементы вектора.

void clear(); 

Пример

// vector_clear.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 10 ); v1.push_back( 20 ); v1.push_back( 30 ); cout
The size of v1 is 3 The size of v1 after clearing is 0 

const_iterator

Тип, предоставляющий итератор произвольного доступа, который может читать элемент const в векторе.

typedef implementation-defined const_iterator; 

Замечания

Тип const_iterator нельзя использовать для изменения значения элемента.

Пример

Пример использования back см. в разделе const_iterator .

const_pointer

Тип, предоставляющий указатель на элемент const в векторе.

typedef typename Allocator::const_pointer const_pointer; 

Замечания

Тип const_pointer нельзя использовать для изменения значения элемента.

Для доступа к элементу вектора обычно используется iterator.

const_reference

Тип, предоставляющий ссылку на const элемент, хранящийся в векторе. Он используется для чтения и выполнения const операций.

typedef typename Allocator::const_reference const_reference; 

Замечания

Тип const_reference нельзя использовать для изменения значения элемента.

Пример

// vector_const_ref.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 10 ); v1.push_back( 20 ); const vector v2 = v1; const int &i = v2.front( ); const int &j = v2.back( ); cout 
The first element is 10 The second element is 20 

const_reverse_iterator

Тип, предоставляющий итератор произвольного доступа, который может читать любой элемент const в векторе.

typedef std::reverse_iterator const_reverse_iterator; 

Замечания

Тип const_reverse_iterator не может изменить значение элемента и используется для итерации по вектору в обратном направлении.

Пример

См rbegin . пример объявления и использования итератора.

crbegin

Возвращает константный итератор, который указывает на первый элемент в обратном векторе.

const_reverse_iterator crbegin() const; 

Возвращаемое значение

Итератор обратного случайного доступа констант, обращаюющийся к первому элементу в обратном vector или адресу, который был последним элементом в необратимом vector .

Замечания

Возвращаемое значение crbegin vector объекта невозможно изменить.

Пример

// vector_crbegin.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::iterator v1_Iter; vector ::const_reverse_iterator v1_rIter; v1.push_back( 1 ); v1.push_back( 2 ); v1_Iter = v1.begin( ); cout
The first element of vector is 1. The first element of the reversed vector is 2. 

crend

Возвращает обратный итератор, указывающий const на элемент после последнего элемента обратного вектора.

const_reverse_iterator crend() const; 

Возвращаемое значение

Обратный const итератор в прошлом для обратного вектора. Он указывает на элемент после последнего элемента обратного вектора, который совпадает с элементом перед первым элементом ненавернутого вектора. Этот элемент является заполнителем и не должен быть разоменован. Используйте его только для сравнения.

Замечания

crend используется с обратным vector так же, как vector::cend используется с vector .

Возвращаемое значение crend (подходящее уменьшение), vector объект не может быть изменен.

crend используется, чтобы проверить, достиг ли итератор конца vector .

Возвращаемое crend значение не должно быть разоменовывано. Используйте его только для сравнения.

Пример

// vector_crend.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::const_reverse_iterator v1_rIter; v1.push_back( 1 ); v1.push_back( 2 ); for ( v1_rIter = v1.rbegin( ) ; v1_rIter != v1.rend( ) ; v1_rIter++ ) cout

data

Возвращает указатель на первый элемент в векторе.

const_pointer data() const; pointer data(); 

Возвращаемое значение

Указатель на первый элемент в vector расположении или в расположении успешно пустой vector .

Пример

// vector_data.cpp // compile with: /EHsc #include #include int main() < using namespace std; vectorc1; vector::pointer c1_ptr; vector::const_pointer c1_cPtr; c1.push_back(1); c1.push_back(2); cout cout cout
The vector c1 contains elements: 1 2 The vector c1 now contains elements: 20 2 

difference_type

Тип, предоставляющий разницу между двумя итераторами, ссылающимися на элементы в одном и том же векторе.

typedef typename Allocator::difference_type difference_type; 

Замечания

difference_type также можно описать как число элементов между двумя указателями, так как указатель на элемент содержит его адрес.

Для доступа к элементу вектора обычно используется iterator.

Пример

// vector_diff_type.cpp // compile with: /EHsc #include #include #include int main( ) < using namespace std; vector c1; vector ::iterator c1_Iter, c2_Iter; c1.push_back( 30 ); c1.push_back( 20 ); c1.push_back( 30 ); c1.push_back( 10 ); c1.push_back( 30 ); c1.push_back( 20 ); c1_Iter = c1.begin( ); c2_Iter = c1.end( ); vector ::difference_type df_typ1, df_typ2, df_typ3; df_typ1 = count( c1_Iter, c2_Iter, 10 ); df_typ2 = count( c1_Iter, c2_Iter, 20 ); df_typ3 = count( c1_Iter, c2_Iter, 30 ); cout
The number '10' is in c1 collection 1 times. The number '20' is in c1 collection 2 times. The number '30' is in c1 collection 3 times. 

emplace

Вставляет элемент, созданный на месте, в указанное положение в векторе.

template iterator emplace( const_iterator position, Types&&. args); 

Параметры

position
Позиция в vector месте вставки первого элемента.

args
Аргументы конструктора. Функция определяет перегрузку конструктора, которую нужно вызвать, на основе переданных аргументов.

Возвращаемое значение

Функция возвращают итератор, указывающий на положение вставки нового элемента в vector .

Замечания

Любая операция вставки может быть дорогой, см vector . класс для обсуждения vector производительности.

Пример

// vector_emplace.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::iterator Iter; v1.push_back( 10 ); v1.push_back( 20 ); v1.push_back( 30 ); cout << "v1 =" ; for ( Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ ) cout << " " << *Iter; cout << endl; // initialize a vector of vectors by moving v1 vector < vector > vv1; vv1.emplace( vv1.begin(), move( v1 ) ); if ( vv1.size( ) != 0 && vv1[0].size( ) != 0 ) < cout > 
v1 = 10 20 30 vv1[0] = 10 20 30 

emplace_back

Добавляет элемент, созданный на месте, в конец вектора.

template void emplace_back(Types&&. args); 

Параметры

args
Аргументы конструктора. Функция определяет перегрузку конструктора, которую нужно вызвать, на основе переданных аргументов.

Пример

#include struct obj < obj(int, double) <>>; int main() < std::vectorv; v.emplace_back(1, 3.14); // obj in created in place in the vector > 

empty

Проверяет, пуст ли вектор.

bool empty() const; 

Возвращаемое значение

true Значение false Значение , если вектор не пуст.

Пример

// vector_empty.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 10 ); if ( v1.empty( ) ) cout
The vector is not empty. 

end

Возвращает итератор, указывающий на элемент после последнего элемента вектора.

iterator end(); const_iterator end() const; 

Возвращаемое значение

Итератор последнего итератора для вектора. Он указывает на элемент после последнего элемента вектора. Этот элемент является заполнителем и не должен быть разоменован. Используйте его только для сравнения. Если вектор пуст, то vector::end() == vector::begin() .

Замечания

Если возвращаемое значение end присваивается переменной типа const_iterator , объект вектора не может быть изменен. Если возвращаемое значение end присваивается переменной типа iterator , объект вектора можно изменить.

Пример

// vector_end.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::iterator v1_Iter; v1.push_back( 1 ); v1.push_back( 2 ); for ( v1_Iter = v1.begin( ) ; v1_Iter != v1.end( ) ; v1_Iter++ ) cout

erase

Удаляет элемент или диапазон элементов в векторе из заданных позиций.

iterator erase( const_iterator position); iterator erase( const_iterator first, const_iterator last); 

Параметры

position
Положение элемента, удаляемого из вектора.

first
Положение первого элемента, удаляемого из вектора.

last
Положение после последнего элемента, удаляемого из вектора.

Возвращаемое значение

Итератор, указывающий на первый элемент, оставшийся после удаленных элементов, или на указатель конца вектора, если такого элемента не существует.

Пример

// vector_erase.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::iterator Iter; v1.push_back( 10 ); v1.push_back( 20 ); v1.push_back( 30 ); v1.push_back( 40 ); v1.push_back( 50 ); cout
v1 = 10 20 30 40 50 v1 = 20 30 40 50 v1 = 20 50 

front

Возвращает ссылку на первый элемент в векторе.

reference front(); const_reference front() const; 

Возвращаемое значение

Ссылка на первый элемент в объекте вектора. Если вектор пуст, возвращаемое значение не определено.

Замечания

Если возвращаемое значение front назначено объекту const_reference , объект вектора не может быть изменен. Если возвращаемое значение front присвоено reference , то объект вектора можно изменить.

При компиляции с помощью _ITERATOR_DEBUG_LEVEL 1 или 2 ошибка среды выполнения возникает при попытке доступа к элементу в пустом векторе. Дополнительные сведения см. в разделе "Проверенные итераторы".

Пример

// vector_front.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 10 ); v1.push_back( 11 ); int& i = v1.front( ); const int& ii = v1.front( ); cout 

get_allocator

Возвращает копию объекта allocator, используемого для создания вектора.

Allocator get_allocator() const; 

Возвращаемое значение

Распределитель, используемый вектором.

Замечания

Распределители для класса вектора определяют, как этот класс управляет хранилищем. Распределители по умолчанию для классов контейнеров из стандартной библиотеки C++ достаточны для большинства задач программирования. Написание и использование собственного класса распределителя — это расширенная функция C++.

Пример

// vector_get_allocator.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; // The following lines declare objects that use the default allocator. vectorv1; vector  v2 = vector (allocator( )) ; // v3 will use the same allocator class as v1 vector v3( v1.get_allocator( ) ); vector::allocator_type xvec = v3.get_allocator( ); // You can now call functions on the allocator class used by vec > 

insert

Вставляет элемент или многие элементы или диапазон элементов в вектор по заданной позиции.

iterator insert( const_iterator position, const Type& value); iterator insert( const_iterator position, Type&& value); void insert( const_iterator position, size_type count, const Type& value); template void insert( const_iterator position, InputIterator first, InputIterator last); 

Параметры

position
Позиция в векторе, куда вставляется первый элемент.

value
Значение элемента, вставляемого в вектор.

count
Количество элементов, вставляемых в вектор.

first
Положение первого элемента в диапазоне копируемых элементов.

last
Положение первого элемента после диапазона копируемых элементов.

Возвращаемое значение

Две первые функции insert возвращают итератор, указывающий на положение вставки нового элемента в вектор.

Замечания

Используемые в качестве предусловия first и last не должны быть итераторами в векторе, в противном случае поведение будет неопределенным. Любая операция вставки может быть дорогой, см vector . класс для обсуждения vector производительности.

Пример

// vector_insert.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::iterator Iter; v1.push_back( 10 ); v1.push_back( 20 ); v1.push_back( 30 ); cout << "v1 =" ; for ( Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ ) cout << " " << *Iter; cout << endl; v1.insert( v1.begin( ) + 1, 40 ); cout << "v1 ="; for ( Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ ) cout << " " << *Iter; cout << endl; v1.insert( v1.begin( ) + 2, 4, 50 ); cout << "v1 ="; for ( Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ ) cout << " " << *Iter; cout << endl; const auto v2 = v1; v1.insert( v1.begin( )+1, v2.begin( )+2, v2.begin( )+4 ); cout << "v1 ="; for (Iter = v1.begin( ); Iter != v1.end( ); Iter++ ) cout << " " << *Iter; cout << endl; // initialize a vector of vectors by moving v1 vector < vector > vv1; vv1.insert( vv1.begin(), move( v1 ) ); if ( vv1.size( ) != 0 && vv1[0].size( ) != 0 ) < cout > 
v1 = 10 20 30 v1 = 10 40 20 30 v1 = 10 40 50 50 50 50 20 30 v1 = 10 50 50 40 50 50 50 50 20 30 vv1[0] = 10 50 50 40 50 50 50 50 20 30 

iterator

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

typedef implementation-defined iterator; 

Замечания

Тип iterator можно использовать для изменения значения элемента.

Пример

Пример см. в примере begin .

max_size

Возвращает максимальную длину вектора.

size_type max_size() const; 

Возвращаемое значение

Максимально возможная длина вектора.

Пример

// vector_max_size.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::size_type i; i = v1.max_size( ); cout

operator[]

Возвращает ссылку на элемент вектора в указанной позиции.

reference operator[](size_type position); const_reference operator[](size_type position) const; 

Параметры

position
Позиция элемента вектора.

Возвращаемое значение

Если заданная позиция больше или равна размеру контейнера, результат не определен.

Замечания

Если возвращаемое значение operator[] назначено объекту const_reference , объект вектора не может быть изменен. Если возвращаемое значение operator[] присвоено ссылке, то объект вектора можно изменить.

При компиляции, _ITERATOR_DEBUG_LEVEL определяемой как 1 или 2, возникает ошибка среды выполнения при попытке получить доступ к элементу за пределами вектора. Дополнительные сведения см. в разделе "Проверенные итераторы".

Пример

// vector_op_ref.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; v1.push_back( 10 ); v1.push_back( 20 ); int& i = v1[1]; cout

operator=

Заменяет элементы вектора копией другого вектора.

vector& operator=(const vector& right); vector& operator=(vector&& right); 

Параметры

right
Копируемый vector в . vector

Замечания

После удаления всех существующих элементов в объекте vector operator= копирует или перемещает содержимое right в объект vector .

Пример

// vector_operator_as.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vectorv1, v2, v3; vector::iterator iter; v1.push_back(10); v1.push_back(20); v1.push_back(30); v1.push_back(40); v1.push_back(50); cout 

pointer

Тип, предоставляющий указатель на элемент в векторе.

typedef typename Allocator::pointer pointer; 

Замечания

Тип pointer можно использовать для изменения значения элемента.

Пример

// vector_pointer.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vectorv; v.push_back( 11 ); v.push_back( 22 ); vector::pointer ptr = &v[0]; cout
11 22 44 

pop_back

Удаляет элемент в конце вектора.

void pop_back(); 

Замечания

Пример кода см. в разделе vector::push_back().

push_back

Добавляет элемент в конец вектора.

void push_back(const T& value); void push_back(T&& value); 

Параметры

value
Значение, назначаемое элементу, который добавляется в конец вектора.

Пример

// compile with: /EHsc /W4 #include #include using namespace std; template void print_elem(const T& t) < cout template void print_collection(const T& t) < cout cout int main() < vectorv; for (int i = 0; i < 10; ++i) < v.push_back(10 + i); >cout > 

rbegin

Возвращает итератор, указывающий на первый элемент в обратном векторе.

reverse_iterator rbegin(); const_reverse_iterator rbegin() const; 

Возвращаемое значение

Обратный итератор произвольного доступа, указывающий на первый элемент в обратном векторе или на последний элемент в исходном векторе.

Замечания

Если возвращаемое значение rbegin назначено объекту const_reverse_iterator , объект вектора не может быть изменен. Если возвращаемое значение rbegin присвоено reverse_iterator , то объект вектора можно изменить.

Пример

// vector_rbegin.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::iterator v1_Iter; vector ::reverse_iterator v1_rIter; v1.push_back( 1 ); v1.push_back( 2 ); v1_Iter = v1.begin( ); cout
The first element of vector is 1. The first element of the reversed vector is 2. 

reference

Тип, предоставляющий ссылку на элемент, хранящийся в векторе.

typedef typename Allocator::reference reference; 

Пример

См at . пример использования reference в классе векторов.

rend

Возвращает обратный итератор, указывающий на элемент после последнего элемента обратного вектора.

const_reverse_iterator rend() const; reverse_iterator rend(); 

Возвращаемое значение

Обратный итератор в прошлом для обратного вектора. Он указывает на элемент после последнего элемента обратного вектора, который совпадает с элементом перед первым элементом ненавернутого вектора. Этот элемент является заполнителем и не должен быть разоменован. Используйте его только для сравнения.

Замечания

rend используется с обратным вектором так же, как end и с вектором.

Если возвращаемое значение rend назначено объекту const_reverse_iterator , объект вектора не может быть изменен. Если возвращаемое значение rend присвоено reverse_iterator , то объект вектора можно изменить.

rend используется, чтобы проверить, достиг ли обратный итератор конца вектора.

Возвращаемое rend значение не должно быть разоменовывано. Используйте его только для сравнения.

Пример

// vector_rend.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::reverse_iterator v1_rIter; v1.push_back( 1 ); v1.push_back( 2 ); for ( v1_rIter = v1.rbegin( ) ; v1_rIter != v1.rend( ) ; v1_rIter++ ) cout

reserve

Резервирует минимальную длину хранилища для объекта вектора, при необходимости выделяя пространство.

void reserve(size_type count); 

Параметры

count
Минимальная длина хранилища, выделяемого для вектора.

Пример

// vector_reserve.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; //vector ::iterator Iter; v1.push_back( 1 ); cout
Current capacity of v1 = 1 Current capacity of v1 = 20 

resize

Определяет новый размер вектора.

void resize(size_type new_size); void resize(size_type new_size, Type value); 

Параметры

new_size
Новый размер вектора.

value
Значение инициализации новых элементов, добавленных в вектор, если новый размер больше исходного. Если значение опущено, новые объекты используют конструктор по умолчанию.

Замечания

Если размер контейнера меньше запрошенного размера, new_size resize добавляет элементы в вектор, пока он не достигнет запрошенного размера. Если размер контейнера превышает запрошенный размер, удаляет элементы, ближайшие к концу контейнера, resize пока он не достигнет размера new_size . Никаких действий не выполняется, если размер контейнера совпадает с запрошенным размером.

size отражает текущий размер вектора.

Пример

// vectorsizing.cpp // compile with: /EHsc /W4 // Illustrates vector::reserve, vector::max_size, // vector::resize, vector::resize, and vector::capacity. // // Functions: // // vector::max_size - Returns maximum number of elements vector could // hold. // // vector::capacity - Returns number of elements for which memory has // been allocated. // // vector::size - Returns number of elements in the vector. // // vector::resize - Reallocates memory for vector, preserves its // contents if new size is larger than existing size. // // vector::reserve - Allocates elements for vector to ensure a minimum // size, preserving its contents if the new size is // larger than existing size. // // vector::push_back - Appends (inserts) an element to the end of a // vector, allocating memory for it if necessary. // ////////////////////////////////////////////////////////////////////// // The debugger cannot handle symbols more than 255 characters long. // The C++ Standard Library often creates symbols longer than that. // The warning can be disabled: //#pragma warning(disable:4786) #include #include #include using namespace std; template void print(const string& s, const C& c) < cout cout void printvstats(const vector& v) < cout << " the vector's size is: " << v.size() << endl; cout << " the vector's capacity is: " << v.capacity() << endl; cout << " the vector's maximum size is: " << v.max_size() int main() < // declare a vector that begins with 0 elements. vectorv; // Show statistics about vector. cout cout 

reverse_iterator

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

typedef std::reverse_iterator reverse_iterator; 

Замечания

Тип reverse_iterator используется для последовательного прохождения через вектор в обратную сторону.

Пример

Пример см. в примере rbegin .

shrink_to_fit

Удаляет лишнюю емкость.

void shrink_to_fit(); 

Пример

// vector_shrink_to_fit.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; //vector ::iterator Iter; v1.push_back( 1 ); cout
Current capacity of v1 = 1 Current capacity of v1 = 20 Current capacity of v1 = 1 

size

Возвращает количество элементов в векторе.

size_type size() const; 

Возвращаемое значение

Текущая длина вектора.

Пример

// vector_size.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1; vector ::size_type i; v1.push_back( 1 ); i = v1.size( ); cout
Vector length is 1. Vector length is now 2. 

size_type

Тип, считающий количество элементов в векторе.

typedef typename Allocator::size_type size_type; 

Пример

Пример см. в примере capacity .

swap

Меняет местами элементы двух векторов.

void swap( vector& right); friend void swap( vector& left, vector& right); 

Параметры

right
Вектор, предоставляющий элементы для замены. Или вектор, элементы которого необходимо обмениваться элементами в векторе left .

left
Вектор, элементы которого необходимо обмениваться элементами в векторе right .

Пример

// vector_swap.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector v1, v2; v1.push_back( 1 ); v1.push_back( 2 ); v1.push_back( 3 ); v2.push_back( 10 ); v2.push_back( 20 ); cout
The number of elements in v1 = 3 The number of elements in v2 = 2 The number of elements in v1 = 2 The number of elements in v2 = 3 

value_type

Тип, представляющий тип данных, хранящихся в векторе.

typedef typename Allocator::value_type value_type; 

Замечания

value_type является синонимом для параметра-шаблона Type .

Пример

// vector_value_type.cpp // compile with: /EHsc #include #include int main( ) < using namespace std; vector::value_type AnInt; AnInt = 44; cout

vector

Создает вектор. Перегрузки создают вектор определенного размера или элементы определенного значения. Или, как копия всех или части другого вектора. Некоторые перегрузки также позволяют указать используемый распределитель.

vector(); explicit vector(const Allocator& allocator); explicit vector(size_type count); vector(size_type count, const Type& value); vector(size_type count, const Type& value, const Allocator& allocator); vector(const vector& source); vector(vector&& source); vector(initializer_list init_list, const Allocator& allocator); template vector(InputIterator first, InputIterator last); template vector(InputIterator first, InputIterator last, const Allocator& allocator); 

Параметры

allocator
Класс распределителя для использования с данным объектом. get_allocator возвращает класс распределителя для объекта.

count
Количество элементов в создаваемом векторе.

value
Значение элементов в создаваемом векторе.

source
Вектор, для которого создаваемый вектор станет копией.

first
Положение первого элемента в диапазоне копируемых элементов.

last
Положение первого элемента за пределами диапазона копируемых элементов.

init_list
Содержащий initializer_list элементы для копирования.

Замечания

Все конструкторы хранят объект распределителя ( allocator ) и инициализировать вектор.

Первые два конструктора определяют пустой исходный вектор. Второй конструктор явно указывает тип распределителя ( allocator ) для использования.

Третий конструктор задает повторение указанного числа ( count ) элементов со значением по умолчанию для класса Type .

Четвертый и пятый конструкторы указывают повторение ( count ) элементов значения value .

Шестой конструктор задает копию вектора source .

Седьмой конструктор перемещает вектор source .

Восьмой конструктор использует initializer_list, чтобы указать элементы.

Девятый и десятый конструкторы копируют диапазон [ first , last ) вектора.

Пример

// vector_ctor.cpp // compile with: /EHsc #include #include int main() < using namespace std; vector ::iterator v1_Iter, v2_Iter, v3_Iter, v4_Iter, v5_Iter, v6_Iter; // Create an empty vector v0 vector v0; // Create a vector v1 with 3 elements of default value 0 vector v1(3); // Create a vector v2 with 5 elements of value 2 vector v2(5, 2); // Create a vector v3 with 3 elements of value 1 and with the allocator // of vector v2 vector v3(3, 1, v2.get_allocator()); // Create a copy, vector v4, of vector v2 vector v4(v2); // Create a new temporary vector for demonstrating copying ranges vector v5(5); for (auto i : v5) < v5[i] = i; >// Create a vector v6 by copying the range v5[ first, last) vector v6(v5.begin() + 1, v5.begin() + 3); cout cout cout cout cout cout cout << endl; // Move vector v2 to vector v7 vector v7(move(v2)); vector ::iterator v7_Iter; cout cout << endl; cout << "v8 ="; vectorv8 < < 1, 2, 3, 4 >>; for (auto& v : v8) < cout cout
v1 = 0 0 0 v2 = 2 2 2 2 2 v3 = 1 1 1 v4 = 2 2 2 2 2 v5 = 0 0 0 0 0 v6 = 0 0 v7 = 2 2 2 2 2 v8 = 1 2 3 4 

Как вернуть вектор из функции c

Для добавления элементов в вектор применяется функция push_back() , в которую передается добавляемый элемент:

#include #include int main() < std::vectornumbers; // пустой вектор numbers.push_back(5); numbers.push_back(3); numbers.push_back(10); for(int n : numbers) cout << n << "\t"; // 5 3 10 std::cout

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

Функция emplace_back() выполняет аналогичную задачу - добавляет элемент в конец контейнера:

std::vector numbers< 1, 2, 3, 4, 5 >; numbers.emplace_back(8); // numbers = < 1, 2, 3, 4, 5, 8 >;

Добавление элементов на определенную позицию

Ряд функций позволяет добавлять элементы на определенную позицию.

  • emplace(pos, value) : вставляет элемент value на позицию, на которую указывает итератор pos
  • insert(pos, value) : вставляет элемент value на позицию, на которую указывает итератор pos, аналогично функции emplace
  • insert(pos, n, value) : вставляет n элементов value начиная с позиции, на которую указывает итератор pos
  • insert(pos, begin, end) : вставляет начиная с позиции, на которую указывает итератор pos, элементы из другого контейнера из диапазона между итераторами begin и end
  • insert(pos, values) : вставляет список значений начиная с позиции, на которую указывает итератор pos
std::vector numbers< 1, 2, 3, 4, 5 >; auto iter = numbers.cbegin(); // константный итератор указывает на первый элемент numbers.emplace(iter + 2, 8); // добавляем после второго элемента numbers = < 1, 2, 8, 3, 4, 5>;
std::vector numbers1< 1, 2, 3, 4, 5 >; auto iter1 = numbers1.cbegin(); // константный итератор указывает на первый элемент numbers1.insert(iter1 + 2, 8); // добавляем после второго элемента //numbers1 = < 1, 2, 8, 3, 4, 5>; std::vector numbers2 < 1, 2, 3, 4, 5 >; auto iter2 = numbers2.cbegin(); // константный итератор указывает на первый элемент numbers2.insert(iter2 + 1, 3, 4); // добавляем после первого элемента три четверки //numbers2 = < 1, 4, 4, 4, 2, 3, 4, 5>; std::vector values < 10, 20, 30, 40, 50 >; std::vector numbers3 < 1, 2, 3, 4, 5 >; auto iter3 = numbers3.cbegin(); // константный итератор указывает на первый элемент // добавляем после первого элемента три первых элемента из вектора values numbers3.insert(iter3 + 1, values.begin(), values.begin() + 3); //numbers3 = < 1, 10, 20, 30, 2, 3, 4, 5>; std::vector numbers4 < 1, 2, 3, 4, 5 >; auto iter4 = numbers4.cend(); // константный итератор указывает на позицию за последним элементом // добавляем в конец вектора numbers4 элементы из списка < 21, 22, 23 >numbers4.insert(iter4, < 21, 22, 23 >); //numbers4 = < 1, 2, 3, 4, 5, 21, 22, 23>;

Удаление элементов

Если необходимо удалить все элементы вектора, то можно использовать функцию clear :

std::vector v < 1,2,3,4 >; v.clear();

Функция pop_back() удаляет последний элемент вектора:

std::vector v < 1,2,3,4 >; v.pop_back(); // v =

Если нужно удалить элемент из середины или начала контейнера, применяется функция std::erase() , которая имеет следующие формы:

  • erase(p) : удаляет элемент, на который указывает итератор p. Возвращает итератор на элемент, следующий после удаленного, или на конец контейнера, если удален последний элемент
  • erase(begin, end) : удаляет элементы из диапазона, на начало и конец которого указывают итераторы begin и end. Возвращает итератор на элемент, следующий после последнего удаленного, или на конец контейнера, если удален последний элемент

std::vector numbers1 < 1, 2, 3, 4, 5, 6 >; auto iter = numbers1.cbegin(); // указатель на первый элемент numbers1.erase(iter + 2); // удаляем третий элемент // numbers1 = < 1, 2, 4, 5, 6 >std::vector numbers2 = < 1, 2, 3, 4, 5, 6 >; auto begin = numbers2.cbegin(); // указатель на первый элемент auto end = numbers2.cend(); // указатель на последний элемент numbers2.erase(begin + 2, end - 1); // удаляем с третьего элемента до последнего // numbers2 =

Также начиная со стандарта С++20 в язык была добавлена функция std::erase() . Она не является частью типа vector. В качестве первого параметра она принимает вектор, а в качестве второго - элемент, который надо удалить:

std::vector numbers3 < 1, 2, 3, 1, 5, 6 >; std::erase(numbers3, 1); // numbers3 =

В данном случае удаляем из вектора numbers3 все вхождения числа 1.

Размер вектора

С помощью функции size() можно узнать размер вектора, а с помощью функции empty() проверить, путой ли вектор:

#include #include int main() < std::vectornumbers; if(numbers.empty()) std::cout

С помощью функции resize() можно изменить размер вектора. Эта функция имеет две формы:

  • resize(n) : оставляет в векторе n первых элементов. Если вектор содержит больше элементов, то его размер усекается до n элементов. Если размер вектора меньше n, то добавляются недостающие элементы и инициализируются значением по умолчанию
  • resize(n, value) : также оставляет в векторе n первых элементов. Если размер вектора меньше n, то добавляются недостающие элементы со значением value

std::vector numbers1 < 1, 2, 3, 4, 5, 6 >; numbers1.resize(4); // оставляем первые четыре элемента - numbers1 = numbers1.resize(6, 8); // numbers1 =

Важно учитывать, что применение функции resize может сделать некорректными все итераторы, указатели и ссылки на элементы.

Изменение элементов вектора

Функция assign() позволяет заменить все элементы вектора определенным набором:

std::vector langs = < "Java", "JavaScript", "C">; langs.assign(4, "C++"); // langs =

В данном случае элементы вектора заменяются набором из четырех строк "C++".

Также можно передать непосредственно набор значений, который заменит значения вектора:

std::vector langs< "Java", "JavaScript", "C">; langs.assign(< "C++", "C#", "C">); // langs =

Еще одна функция - swap() обменивает значения двух контейнеров:

std::vector clangs < "C++", "C#", "Java" >; std::vector ilangs < "JavaScript", "Python", "PHP">; clangs.swap(ilangs); // clangs = < "JavaScript", "Python", "PHP">; for(std::string lang : clangs)

Сравнение векторов

Векторы можно сравнивать - они поддерживают все операции сравнения: , =, ==, !=. Сравнение контейнеров осуществляется на основании сравнения пар элементов на тех же позициях. Векторы равны, если они содержат одинаковые элементы на тех же позициях. Иначе они не равны:

std::vector v1 ; std::vector v2 ; std::vector v3 ; bool v1v2 = v1 == v2; // true bool v1v3 = v1 != v3; // true bool v2v3 = v2 == v3; // false

Как вернуть vector из функции: по значению или по ссылке?

Есть функция, создающая каким-то определенным образом экземпляр vector . Вопрос: как вернуть этот экземпляр вызывающему?

Правильное с точки зрения логики и стройности программы решение выглядит так:

std::vectorint> create_vector(const size_t N) std::vectorint> v; v.resize(N, 0xDEADC0DE); return v; > 

Тут экземпляр вектора возвращается по значению, что означает потенциальное глубокое копирование локального объекта в контекст вызывающей функции. Сразу возникает сомнение: а что, если вектор огромен - его ж надо будет побайтно перекладывать из одного места в другое? Гораздо “разумнее” было бы написать:

void create_vector(const size_t N, std::vectorint>* v) v->resize(N, 0xDEADC0DE); > 

Тут вектор передается по указателю, и стопроцентно ненужного полного копирования не будет. Но такой код выглядит откровенно плохо.

Сравним скорости работы на векторе длиной 100MB. Например, на компиляторе:

Apple clang version 3.1 (tags/Apple/clang-318.0.45) (based on LLVM 3.1svn) Target: x86_64-apple-darwin11.3.0 
#include #include std::vectorint> __attribute__((noinline)) create_vector(const size_t N) std::cout  <"by value"  ::endl; std::vectorint> v; v.resize(N, 0xDEADC0DE); return v; > int main(int argc, char* argv[]) for (size_t i = 0; i  10; ++i) const size_t N = 1024 * 1024 * 100; std::vectorint> v = create_vector(N); if (v[i] != 0xDEADC0DE) std::cout  <"Test is rubbish"  ::endl; return 0; > > return 0; > 
clang++ -O3 -o by_value by_value.cpp && time ./by_value 
0m4.933s 

Теперь по указателю:

#include #include void __attribute__((noinline)) create_vector(const size_t N, std::vectorint>* v) std::cout  <"by pointer"  ::endl; v->resize(N, 0xDEADC0DE); > int main(int argc, char* argv[]) for (size_t i = 0; i  10; ++i) const size_t N = 1024 * 1024 * 100; std::vectorint> v; create_vector(N, &v); if (v[i] != 0xDEADC0DE) std::cout  <"Test is rubbish"  ::endl; return 0; > > return 0; > 
clang++ -O3 -o by_pointer by_pointer.cpp && time ./by_pointer 
0m4.852s 

Время в обоих случаях одинаково. Получается, что стоит выбрать первый, “красивый” вариант.

Объяснений тут два. Первый, и возможно самый важный - это RVO, Return value optimization. Это когда компилятор догадывается, что создаваемый локальный экземпляр вектора предназначен для возврата из функции, и сразу создает его в контексте вызывающего кода, чтобы потом не копировать туда. Фактически компилятор реализует передачу по ссылке, но неявно, не портя красоту исходного кода. Данный трюк будет работать для любого класса, не обязательно класса из STL.

Но оптимизация - это негарантированная вещь. Но тут есть еще одно подспорье. Стандартные контейнеры STL реализованы так, что при даже при глубоком копировании фактически копируется только небольшая управляющая структура, а сами данные, размещенные в куче, просто перебрасываются указателем, без их фактического перемещения. Тут, конечно, будет небольшое дополнительное копирование, но оно минимально, и возможно на него стоит пойти ради сохранения красивого кода.

Ну а в контексте C++11, где есть семантика перемещения, вообще не будет лишних копирований, если класс “правильно” реализован (что верно для классов из STL).

Мораль: используйте по возможности контейнеры из STL и оставьте оптимизацию компилятору. Иногда, конечно, компилятор ошибается, но таких случаев гораздо меньше, чем наоборот.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *