An in depth analysis of the usage of STL vector

  • 2020-05-05 11:41:15
  • OfStack

This article is very detailed about the usage of stl vector, please refer to

below for details

introduces

The purpose of this article is to introduce std::vector, how to properly use their member functions and so on. This article also discusses the use of conditional functions and function Pointers in iterative algorithms, such as remove_if() and for_each(). By reading this article, you should be able to use the vector container effectively, and you should no longer use dynamic arrays of the C type.

Vector overview

vector is part of the C++ standard template library, which is a versatile template class and library that can manipulate a variety of data structures and algorithms. vector is considered a container because it can hold objects of all types just like a container. Simply put, vector is a dynamic array that can hold any type of object, and can add and compress data.

In order to use vector, you must include the following code in your header file:


#include <vector>

vector belongs to the std naming domain, so you need to pass the naming qualification. Complete your code as follows:


using std::vector;
vector<int> vInts;

Or together, use the full name:

std::vector < int > vInts;

A global naming field approach is recommended:

using namespace std;

The global naming of fields can cause problems in later operations. The vector container provides many interfaces, and the member functions and operations of vector are listed in the following table.

Vector member function

函数

表述

c.assign(beg,end)

c.assign(n,elem)

[beg; end)区间中的数据赋值给c

nelem的拷贝赋值给c

c.at(idx)

传回索引idx所指的数据,如果idx越界,抛出out_of_range

c.back()

传回最后一个数据,不检查这个数据是否存在。

c.begin()

传回迭代器重的可一个数据。

c.capacity()

返回容器中数据个数。

c.clear()

移除容器中所有数据。

c.empty()

判断容器是否为空。

c.end()

指向迭代器中的最后一个数据地址。

c.erase(pos)

c.erase(beg,end)

删除pos位置的数据,传回下一个数据的位置。

删除[beg,end)区间的数据,传回下一个数据的位置

c.front()

传回第一个数据。

get_allocator

使用构造函数返回一个拷贝。

c.insert(pos,elem)

c.insert(pos,n,elem)

c.insert(pos,beg,end)

pos位置插入一个elem拷贝,传回新数据位置。

pos位置插入nelem数据。无返回值。

pos位置插入在[beg,end)区间的数据。无返回值。

c.max_size()

返回容器中最大数据的数量。

c.pop_back()

删除最后一个数据。

c.push_back(elem)

在尾部加入一个数据。

c.rbegin()

传回一个逆向队列的第一个数据。

c.rend()

传回一个逆向队列的最后一个数据的下一个位置。

c.resize(num)

重新指定队列的长度。

c.reserve()

保留适当的容量。

c.size()

返回容器中实际数据的个数。

c1.swap(c2)

swap(c1,c2)

c1c2元素互换。

同上操作。

vector<Elem> c

vector <Elem> c1(c2)

vector <Elem> c(n)

vector <Elem> c(n, elem)

vector <Elem> c(beg,end)

c.~ vector <Elem>()

创建一个空的vector

复制一个vector

创建一个vector,含有n个数据,数据均已缺省构造产生

创建一个含有nelem拷贝的vector

创建一个以[beg;end)区间的vector

销毁所有数据,释放内存。

Vector operation

函数

描述

operator[]

返回容器中指定位置的一个引用。

create an vector

The vector container provides a number of ways to create it, several of which are commonly used.
Create an empty vector object of type Widget:


vector<Widget> vWidgets;
//  ------
//  |
//  |- Since vector is a container, its member functions
//   operate on iterators and the container itself so
//   it can hold objects of any type.

Create an vector:

containing 500 pieces of data of type Widget

vector < Widget > vWidgets(500);
 
Create an vector containing 500 pieces of data of type Widget and initialize them all to 0:

vector < Widget > vWidgets(500, Widget(0));

create a copy of Widget:

vector < Widget > vWidgetsFromAnother(vWidgets);

adds a data

to vector

The default method for adding data to vector is push_back(). The push_back() function adds data to the end of vector and allocates memory as needed. For example: to vector< Widget > To add 10 pieces of data, you need to write the following code:


for(int i= 0;i<10; i++)
 vWidgets.push_back(Widget(i));

gets the location data in vector

Most of the time we don't have to know how much data is in vector, the data in vector is dynamically allocated, and a set of allocation Spaces using push_back() is often determined by the file or some data source. If you want to know how much data vector stores, you can use empty(). To get the size of vector, you can use size(). For example, if you want to get the size of vector v, but don't know if it's empty or if it already contains data, if it's set to -1 for utopia, you can use the following code:
int nSize = v.empty() ? -1 : static_cast < int > (v.size());

accesses data in vector, ,

USES two methods to access vector.

1,     vector::at()
2.     vector::operator[]

operator[] is mainly for compatibility with C language. It works like an C language array. But at() is our first choice, because at() does boundary checking, and an exception is thrown if the access exceeds the scope of vector. operator[] is prone to some errors, so we rarely use it. Here's a check:

Analyze the following code:


vector<int> v;
v.reserve(10);
for(int i=0; i<7; i++)
 v.push_back(i);
try
{
 int iVal1 = v[7]; // not bounds checked - will not throw
 int iVal2 = v.at(7); // bounds checked - will throw if out of range
}
catch(const exception& e)
{
 cout << e.what();
}

  we allocated 10 int Spaces using reserve(), but we did not initialize them.

You can try out different conditions in this code and see what it does, but whenever you use at(), it works.

deletes data from vector

vector is very easy to add data, it is also very easy to retrieve data, vector provides erase(), pop_back(), clear() to delete data, when you delete data, you should know to delete the tail data, or delete all data, or individual data. Let's take a moment to consider some of the applications in STL before we consider things like deleting.

Remove_if() algorithm

Now let's think about manipulating the data inside. To use remove_if(), we need to include the following code in the header file: :
#include < algorithm >

            Remove_if() has three parameters:

1.     iterator _First: iteration pointer to the first data.
2.     iterator _Last: iteration pointer to the last data.
    predicate _Pred: a conditional function that can operate on an iteration.

conditional function

A conditional function is a user-defined condition that returns a yes or no result, is a basic function pointer, or is a function object. This function object needs to support all function call operations, overloading operator()() operations. remove_if() is inherited through unary_function, allowing data to be passed as a condition.

For example, suppose you want to start with an vector< CString >If the string contains a value, start with that value and end with that value. First you should create a data structure to contain this data, similar to


#include <functional>
enum findmodes
{
 FM_INVALID = 0,
 FM_IS,
 FM_STARTSWITH,
 FM_ENDSWITH,
 FM_CONTAINS
};
typedef struct tagFindStr
{
 UINT iMode;
 CString szMatchStr;
} FindStr;
typedef FindStr* LPFINDSTR;

  then handles the conditional judgment:


class FindMatchingString
 : public std::unary_function<CString, bool>
{
public:
 FindMatchingString(const LPFINDSTR lpFS) : m_lpFS(lpFS) {}
 bool operator()(CString& szStringToCompare) const
 {
  bool retVal = false;
  switch(m_lpFS->iMode)
  {
  case FM_IS:
  {
   retVal = (szStringToCompare == m_lpFDD->szMatchStr);
   break;
  }
  case FM_STARTSWITH:
  {
   retVal = (szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength())
    == m_lpFDD->szWindowTitle);
   break;
  }
  case FM_ENDSWITH:
  {
   retVal = (szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength())
    == m_lpFDD->szMatchStr);
   break;
  }
  case FM_CONTAINS:
  {
   retVal = (szStringToCompare.Find(m_lpFDD->szMatchStr) != -1);
   break;
  }
  }
  return retVal;
 }
private:
 LPFINDSTR m_lpFS;
};

  with this operation you can effectively delete data from vector:


// remove all strings containing the value of
// szRemove from vector<CString> vs.
FindStr fs;
fs.iMode = FM_CONTAINS;
fs.szMatchStr = szRemove;
vs.erase(std::remove_if(vs.begin(), vs.end(), FindMatchingString(&fs)), vs.end());

What can Remove_if() do?

You might be wondering, for the example above, how about erase() when you call remove_if()? This is because you are not familiar with the algorithm in STL. Remove(),remove_if(), and so on all move out operations are based on an iterative scope, so the data in the container cannot be manipulated. So when you're using remove_if(), you're actually operating on the top of the data in the container. Consider the above example:

1,     szRemove = "o" 2. See the chart below for     vs.

Looking at this result, we can see that remove_if() actually modifies the iteration address according to the condition, and there is some residual data behind the data, which needs to be deleted. The location of the remaining data may not be the original data, but they don't know.

Call erase() to delete the remaining data. Note that in the above example, erase() is used to delete the results of remove_if() and the data in the vs.enc () range.

compresses a bloated vector

Many times you delete a lot of data, or by using reserve(), and you end up with a lot more vector than you need. All it takes is to compress vector to its actual size. resize() increases the size of vector. Clear() can only change the size of the cache, all of which is important for vector to free up memory and so on. How do we solve these problems? Let's do it.

We can create another vector from one vector. Let's see what happens here. Suppose we already have an vector v with a memory size of 1000, and when we call size() it is only 7. We wasted a lot of memory. Let's create an vector on top of it.

std::vector < CString > vNew(v);
cout < < vNew.capacity();

vNew.capacity() returns 7. This shows that the newly created space is only allocated according to the actual size. Now we don't want to release v, because we're going to use it somewhere else, so we can use swap() to swap v and vNew, right?


 vNew.swap(v);
 cout << vNew.capacity();
 cout << v.capacity();

Interestingly, vNew.capacity () is 1000, while v.capacity () is 7.

Now I have achieved my goal, but it is not a good solution, we can write as follows:

      std::vector < CString > (v).swap(v);

Can you see what we did? We created a temporary variable instead of the named one, and then we used swap(), so we took out the unnecessary space and got the actual size of v.

Conclusion

I hope this document will be a valuable reference for developers using the STL vector container. I also hope that by reading this article you are comfortable using vector instead of C.


Related articles: