Categories
linuxhint.com

How to Use C++ Vector

This article shows you how to use the C++ vector. You will need some knowledge of C++ pointers, references, and arrays to understand this article.

Introduction

An array is a series of same object types in consecutive memory locations. An array cannot increase ore reduce in length. A vector is like an array, but its length can be increased or reduced. A vector, therefore, has many more operations than an array.

C++ has many libraries, all of which form the C++ Standard Library. One of these libraries is the container library. A container is a collection of objects, and certain operations can be performed on the collection. C++ containers can be grouped into two sets: sequence containers and associative containers. Sequence containers are vector, array (not the same array discussed previously), deque, forward_list, and list. These are different collections (array-like data structures), and each offers distinct trade-offs.

Any programmer should know how to decide whether to use a vector, an array, a deque, a forward_list, or a list. When a programmer needs a structure that requires more operations than those associated with an ordinary array, the ordinary array should not be used.

If the task involves frequent insertions and deletions in the middle of the sequence, then a list or forward_list should be used. If the task involves frequent insertions and deletions in the beginning or end of a sequence, then a deque should be used. A vector should be used when these kinds of operations are not required.

This article shows you how to use the C++ vector. You will need some knowledge of C++ pointers, references, and arrays to understand this article.

Class and Objects

A class is a set of variables and functions that work together, where the variables do not have values assigned. When values are assigned to the variables, a class becomes an object. Different values given to the same class result in different objects; that is, different objects can be of the same class but have different values. Creating an object from a class is also known as instantiating the object.

The term vector describes a class. An object created from a vector has a name that is chosen by the programmer.

A function that belongs to a class is needed to instantiate an object from the class. In C++, that function has the same name as the name of the class. Different objects created (instantiated) from the class have distinct names given to each of them by the programmer.

Creating an object from a class means constructing the object; it also means instantiating the object.

The Vector Class

The vector class has already been defined and is in the library. To use the vector class, a programmer must include the vector header in the file with the following preprocessing directive:

#include <vector>

Once the header is included, all the vector features (data members and member functions) become accessible. To use the count object to output data to the terminal (console), the object header must also be included. To write a program with the vector, as a minimum, the following headers must be included:

#include <iostream>
#include <vector>

Instantiating a Vector

int foo [10];

Above is the declaration of an array with the name “foo†and the number of elements “10.†This is an array of integers. The declaration of a vector is similar. For a vector, the number of elements is optional, since the vector length can increase or decrease.

At this point in the program, the vector class has already been defined in the library, and the header has been included. The vector can be instantiated as follows:

std::vector <int> vtr (8);

Here, the vector is of the special constructor function. The type of data the vector will hold is “int,†in angle brackets. The term “vtr†is the name chosen by the programmer for the vector. Finally, “8,†in parentheses, is the tentative number of integers the vector will have.

The term “std†stands for standard namespace. This term must be followed by a double colon, in this context. Anybody can write their own vector class library and use it. However, C++ already has a standard library with standard names, including “vector.†To use a standard name, the standard name must be preceded by std:: . To avoid typing std:: each time in the program for a standard name, the program file can start as follows:

#include <iostream>
#include <vector>
using namespace std;

Overloading a Function

When two or more different function signatures have the same name, that name is said to be overloaded. When one function is called, the number and type of arguments determine which function is executed.

Constructing a Vector

Constructing a vector means instantiating (creating) a vector object. The constructor function is overloaded as follows:

vector <T> name

This creates a vector of length zero and type “T.†The following statement creates a vector of zero length of the type “float†with the name “vtr:â€

vector <float> vtr;

vector <T> name (n)

This creates a vector with n elements of type “T.†A statement for this vector with four float elements is as follows:

vector <float> vtr(4);

vector <T> name (n, t)

This creates a vector of n elements initialized to the value t. The following statement creates a vector of 5 elements, where each element has the value 3.4:

vector <float> vtr (5, 3.4);

Constructing with Initialization

A vector can be constructed (created) and initialized at the same time, in one of the following two ways:

vector <float> vtr = {1.1, 2.2, 3.3, 4.4};

Or

vector <float> vtr{1.1, 2.2, 3.3, 4.4};

Note that there are no parentheses just after the object name. Parentheses used just after the object name should have the initializer list, as follows:

vector <float> vtr({1.1, 2.2, 3.3, 4.4});

A vector can be constructed and initialized later with the initializer list. In this case, the parentheses will not be used:

vector <float> vtr;
vtr = {1.1, 2.2, 3.3, 4.4};

vector <T> V2 (V1)

This is a copy constructor. It creates a vector V2 as a copy of the vector V1. The following code illustrates this:

vector <float> vtr1(5, 3.4);
vector <float> vtr2(vtr1);

Assigning a Vector during Construction

During construction, an empty vector can be created while another one is assigned to it, as follows:

vector <float> vtr1{1.1, 2.2, 3.3, 4.4};
vector <float> vtr2 =vtr1;

The second statement is equivalent to:

vector <float> vtr2 = {1.1, 2.2, 3.3, 4.4};

const Vector

A const vector is a vector whose elements cannot be changed. The values in this vector are read-only. When created, the vector appears as follows:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};

In this vector type, no element can be added or removed. Moreover, no value can be changed.

Constructing with Iterator

A template provides a generic representation for a data type. An iterator provides a generic representation of scanning through the values of a container. The syntax to create a vector with an iterator is as follows:

template<class InputIterator>
vector(InputIterator first, InputIterator last,const Allocator& = Allocator());

This constructs a vector for the range [first, last) using the specified allocator, which will be discussed later in this article.

Destroying a Vector

To destroy a vector, simply allow it to go out of scope and destroy is handled automatically.

Vector Capacity

size_type capacity() const noexcept

The total number of elements the vector can hold without requiring reallocation is returned by the capacity member function. A code segment for this is as follows:

vector <float> vtr(4);
int num = vtr.capacity();
cout << num << n;

The output is 4.

reserve(n)

Memory space is not always freely available. Extra space can be reserved in advance. Consider the following code segment:

vector <float> vtr(4);
vtr.reserve(6);
cout << vtr.capacity() << n;

The output is 6. So, the extra space reserved is 6 – 4 = 2 elements. The function returns void.

size() const noexcept

This returns the number of elements in the vector. The following code illustrates this function:

vector <float> vtr(4);
float sz = vtr.size();
cout << sz << n;

The output is 4.

shrink_to_fit()

After giving extra capacity to a vector with the reserve() function, the vector can be sized down to fit to its original size. The following code illustrates this:

vector <float> vtr(4);
vtr.reserve(6);
vtr.shrink_to_fit();
int sz = vtr.size();
cout << sz << n;

The output is 4 and not 6. The function returns void.

resize(sz), resize(sz,c)

This resizes the vector. If the new size is smaller than the old size, then the elements towards the end are erased. If the new size is longer, then some default value is added towards the end. To have a particular value added, use the resize() function with two arguments. The following code segment illustrates the use of these two functions:

vector <float> vtr1{1.1, 2.2, 3.3, 4.4};
vtr1.resize(2);
cout << “New size of vtr1: “ << vtr1.size() << n;
vector <float> vtr2{1.1, 2.2};
vtr2.resize(4, 8.8);
cout << “vtr2: “<< vtr2[0] <<” “<< vtr2[1] <<
<< vtr2[2] <<” “<< vtr2[3] << n;

The output is the following:

New size of vtr1: 2
vtr2: 1.1 2.2 8.8 8.8

The functions return void.

empty() const noexcept

This function returns 1 for true if there are no elements in the vector and 0 for false if the vector is empty. If a vector has 4 locations for a particular type of data, such as float, without any float value, then that vector is not empty. The following code illustrates this:

vector <float> vtr;
cout << vtr.empty() << n;
vector <float> vt(4);
cout << vt.empty() << n;

vector <float> v(4,3.5);
cout << v.empty() << n;

The output is the following:

1
0
0

Vector Element Access

A vector can be sub-scripted (indexed) like an array. Index counting begins from zero.

vectorName[i]

The operation “vectorName[i]†returns a reference to the element at the ith index of the vector. The following code outputs 3.3 for the above vector:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr[2];
cout << fl << n;

vectorName[i] const

The operation “vectorName[i] const†is executed instead of “vectorName[i]†when the vector is a constant vector. This operation is used in the following code:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr[2];
cout << fl << n;

The expression returns a constant reference to the ith element of the vector.

Assigning a Value with Subscript

A value can be assigned to a non-constant vector, as follows:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vtr[2] = 8.8;
cout << vtr[2] << n;

The output is 8.8.

vectorName.at(i)

“vectorName.at(i)†is like “vectorName[i],†but “vectorName.at(i)†is more reliable. The following code shows how this vector should be used:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr.at(2);
cout << fl << n;
at() is a vector member function.

vectorName.at(i) const

“vectorName.at(i) const†is like “vectorName[i] const,†but “vectorName.at(i) const†is more reliable. “vectorName.at(i) const†is executed instead of “vectorName.at(i)†when the vector is a constant vector. This vector is used in the following code:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr.at(2);
cout << fl << n;
at() const is a vector member function.

Assigning a Value with the at() Function

A value can be assigned to a non-constant vector with the at() function, as follows:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vtr.at(2) = 8.8;
cout << vtr[2] << n;

The output is 8.8.

Problem with Sub-Scripting

The problem with sub-scripting (indexing) is that if the index is out of range, zero may be returned or an error may be issued at run-time.

front()

This returns a reference to the first element of the vector without removing the element. The output of the following code is 1.1.

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr.front();
cout << fl << n;

The element is not removed from the vector.

front() const

When the vector construction is preceded by const, the expression “front() const†is executed instead of “front().†This is used in the following code:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr.front();
cout << fl << n;

A constant reference is returned. The element is not removed from the vector.

back()

This returns a reference to the last element of the vector without removing the element. The output of the following code is 4.4.

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr.back();
cout << fl << n;

back() const

When the vector construction is preceded by const, the expression “back() const†is executed instead of “back().†This is used in the following code:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
float fl = vtr.back();
cout << fl << n;

A constant reference is returned. The element is not removed from the vector.

Vector Data Access

data() noexcept; data() const noexcept;

Either of these returns a pointer such that [data(), data() + size()) is a valid range.

This will be covered in greater detail later in the article.

Returning Iterators and the Vector

An iterator is like a pointer but has more functionality than a pointer.

begin() noexcept

Returns an iterator that points to the first element of the vector, as in the following code segment:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::iterator iter = vtr.begin();
cout << *iter << n;

The output is 1.1. Note that the declaration that receives the iterator has been declared. The iterator is dereferenced in a return expression to obtain the value in the same way that a pointer is dereferenced.

begin() const noexcept;

Returns an iterator that points to the first element of the vector. When the vector construction is preceded by const, the expression “begin() const†is executed instead of “begin().†Under this condition, the corresponding element in the vector cannot be modified. This is used in the following code:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::const_iterator iter = vtr.begin();
cout << *iter << n;

The output is 1.1. Note that “const_iterator†has been used this time instead of just “iterator†to receive the returned iterator.

end() noexcept

Returns an iterator that points immediately beyond the last element of the vector. Consider the following code segment:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::iterator iter = vtr.end();
cout << *iter << n;

The output is 0, which is meaningless, as there is no concrete element beyond the last element.

end() const noexcept

Returns an iterator that points immediately beyond the last element of the vector. When the vector construction is preceded by “const,†the expression “end() const†is executed instead of “end().†Consider the following code segment:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::const_iterator iter = vtr.end();
cout << *iter << n;

The output is 0. Note that “const_iterator†has been used this time instead of just “iterator†to receive the returned iterator.

Reverse Iteration

It is possible to have an iterator that iterates from the end to just before the first element.

rbegin() noexcept

Returns an iterator that points to the last element of the vector, as in the following code segment:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::reverse_iterator rIter = vtr.rbegin();
cout << *rIter << n;

The output is 4.4.

Note that the declaration that receives the reverse iterator has been declared. The iterator is dereferenced in a return expression to obtain the value in the same way that a pointer is dereferenced.

rbegin() const noexcept;

Returns an iterator that points to the last element of the vector. When the vector construction is preceded by “const,†the expression “rbegin() const†is executed instead of “rbegin().†Under this condition, the corresponding element in the vector cannot be modified. This feature is used in the following code:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::const_reverse_iterator rIter = vtr.rbegin();
cout << *rIter << n;

The output is 4.4.

Note that the const_reverse_iterator has been used this time, instead of just the reverse_iterator, to receive the returned iterator.

rend() noexcept

Returns an iterator that points just before the first element of the vector. Consider the following code segment:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::reverse_iterator rIter = vtr.rend();
cout << *rIter << n;

The output is 0, which is meaningless, as there is no concrete element just before the first element.

rend() const noexcept

Returns an iterator that points just before the first element of the vector. When the vector construction is preceded by “const,†the expression “rend() const†is executed instead of “rend().†Consider the following code segment:

const vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vector<float>::const_reverse_iterator rIter = vtr.rend();
cout << *rIter << n;

The output is 0.

Note that the const_reverse_iterator has been used this time, instead of just the reverse_iterator, to receive the returned iterator.

Vector Modifiers

A modifier that modifies the vector can take or return an iterator.

a.emplace(p, args)

Inserts an object of type T constructed with std::forward<Args>(args)… before p.

For details – see later

insert(iteratorPosition, value)

Inserts a copy of the value at the iterator position of the vector. Returns the iterator (position) in the vector where the copy has been placed. The following code shows where the value has been placed:

vector <int> vtr{10, 20, 30, 40};
vector<int>::iterator iter = vtr.begin();
++iter;
++iter;
vtr.insert(iter, 25);
cout << vtr[1] << ‘ ‘ << vtr[2]<<
<< vtr[3] << n;

The output is: 20 25 30.

Note that the iterator was advanced (incremented) just like a pointer.

An initializer list can also be inserted, as the following code illustrates:

vector <int> vtr{10, 20, 30, 40};
vector<int>::iterator iter = vtr.begin();
++iter;
++iter;
vtr.insert(iter, {25, 28});

cout << vtr[1] << ‘ ‘ << vtr[2]<<
 ‘
<< vtr[3]<< ‘ ‘ << vtr[4] << n;

The output is: 20 25 28 30.

erase(position)

Removes an element at the position pointed to by the iterator, then returns the iterator position. The following code illustrates this:

vector <int> vtr{10, 20, 30, 40};
vector<int>::iterator iter = vtr.begin();
++iter;
++iter;
vtr.erase(iter);
cout << vtr[0] << ‘ ‘ << vtr[1] <<
 ‘
<< vtr[2]<< n;

The output is: 10 20 40

push_back(t), push_back(rv)

Used to add a single element at the end of the vector. Use push_back(t) as follows:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vtr.push_back(5.5);
float fl = vtr[4];
cout << fl << n;

The output is 5.5.

push_back(rv): see later.

pop_back()

Removes the last element without returning it. The size of the vector is reduced by 1. The following code illustrates this:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vtr.pop_back();
float sz = vtr.size();
cout << sz << n;

The output is 3.

a.swap(b)

Two vectors can be swapped, as illustrated in the following code segment:

vector <float> vtr1{1.1, 2.2, 3.3, 4.4};
vector <float> vtr2{10, 20};
vtr1.swap(vtr2);
cout << “vtr1: “<< vtr1[0] <<” “<< vtr1[1] <<
 “
<< vtr1[2] <<” “<< vtr1[3] << n;

cout << “vtr2: “<< vtr2[0] <<” “<< vtr2[1] <<
 “
<< vtr2[2] <<” “<< vtr2[3] << n;

The output is:

vtr1: 10 20 0 0
vtr2: 1.1 2.2 3.3 4.4

Note that the length of a vector is increased, if necessary. Also, values that did not have replacements are replaced by some default value.

clear()

Removes all elements from the vector, as the following code segment illustrates:

vector <float> vtr{1.1, 2.2, 3.3, 4.4};
vtr.clear();
cout << vtr.size() << n;

The output is 0.

Equality and Relational Operators for Vectors

The == Operator

Returns 1 for true if the two vectors have the same size and the corresponding elements are equal; otherwise, it returns 0 for false. For example:

vector <int> U{1, 2, 3};
vector <int> V{4, 5, 6};
bool bl = U==V;
cout << bl << n;

The output is 0.

The != Operator

Returns 1 for true if the two vectors do not have the same size and/or the corresponding elements are not equal; otherwise, it returns 0 for false. For example:

vector <int> U{1, 2, 3};
vector <int> V{4, 5, 6};
bool bl = U!=V;
cout << bl << n;

The output is 1.

The < Operator

Returns 1 for true if the first vector is the initial subset of the second vector, with the elements of the two equal portions being the same and in the same order. If both vectors are of the same size and moving from left to right and an element is encountered in the first vector that is less than the corresponding element in the second vector, then 1 will still be returned. Otherwise, 0 for false is returned. For example:

vector <int> U{3, 1, 1};
vector <int> V{3, 2, 1};
bool bl = U<V;
cout << bl << n;

The output is 1. < does not include the case when the size and order are the same.

The > Operator

Returns !(U < V), where U is the first vector and V is the second vector, according to the above definitions.

The <= Operator

Returns U <= V, where U is the first vector and V is the second vector, according to the above definitions.

The >= Operator

Returns !(U <= V), where U is the first vector and V is the second vector, according to the above definitions.

Conclusion

A vector is an example of a sequence container. A vector is a “better†form of the ordinary array and is instantiated from a class. Vectors have methods that are classified under: construction and assignment, capacity, element access, data access, iterators, modifiers, and numerical overloaded operators.

There are other sequence containers, called list, forward_list, and array. If the task involves frequent insertions and deletions in the middle of the sequence, then a list or forward_list should be used. If the task involves frequent insertions and deletions at the beginning or end of the sequence, then a deque should be used. And so, vectors should be used only when these kinds of operations are not important.

Leave a Reply

Your email address will not be published. Required fields are marked *