Vector
Vector
- Hey folks! Today we are going to dive into the world of C++ vectors. In this blog, we will cover the basics of using vectors and explore the fundamental syntax of vectors. We will also touch upon some related techniques that you wonld not want to miss.
- I would like to give a special thanks to @The Cherno for teaching me C++ through his C++ series on YouTube. Please subscribe to his channel if possible!
Brief intro
- Vector is a powerful datatype in the C++ standard library that functions similarly to an array list. Although its name may suggest a relation to mathematical vectors, it is actually quite different. One of its notable features is the ability to dynamically change its size and query its current size. Let’s dive into the details.
Simple demo
- Here is a simple demo to showcase the basic usage of vectors in C++. Most of the important points are explained in the comments:cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Define a struct called Vertex with three float values
struct Vertex
{
float x, y, z;
Vertex(float x, float y, float z)
: x(x), y(y), z(z) // initialization list
{}
};
// Define an overloaded operator<< function to allow printing of Vertex objects to std::cout
std::ostream& operator<<(std::ostream& stream, const Vertex vertex)
{
stream << "(" << vertex.x << ", " << vertex.y << ", " << vertex.z << ")";
return stream;
}
// Main function
int main()
{
std::vector<Vertex> vertices; // create a vector of Vertex objects called vertices
vertices.push_back({ 1, 2, 3 }); // add a new Vertex object with x=1, y=2, and z=3 to the end of the vector
vertices.push_back({ 4, 5, 6 }); // add another Vertex object with x=4, y=5, and z=6 to the end of the vector
// Loop through each element in the vector and print its value using the overloaded << operator
for (int i = 0; i < vertices.size(); i++)
std::cout << vertices[i] << std::endl;
vertices.erase(vertices.begin() + 1); // remove the second element (index 1) from the vector
// Loop through each element in the vector using a range-based for loop and print its value using the overloaded << operator
for (Vertex& v : vertices)
std::cout << v << std::endl;
std::cin.get(); // wait for user input before closing the program
} - Here are some important things to keep in mind when using vectors in C++:
- Make sure to include the vector library in your code so that you can use the vector class.
- Add data to the end of the vector using the push_back() method.
- Remove data using the erase() method with the index of the element you want to remove.
- You can obtain the initial location of the vector by calling the begin() method.
- Unlike Java, where a class is required to be the vector’s data type, in C++, we can use basic types such as int as the vector’s data type
- In this demo, we’ve used some interesting techniques that are worth noting:
- Overloading the << operator to customize output for the vector. (We will talk about overloading operator in another blog)
- Copying data can be slow and inefficient, so using references (&) can help avoid this issue.
- We are using a range-based for loop here, which Python programmers might find familiar.
- The initialization list for Vertex class is defined within the class itself. (Further details about initialization lists may be discussed in a future blog post)
Optimization of vector
- The above simple demo just show basic usage of vector, which can be slow and inefficient without any optimization.
- Normal vectors have various limitations, but for today, we will focus on addressing the issue of copying to improve their performance.
Avoid copy
- The best way to optimize is knowing the environment we are working with. Thus, we need to identify where the vector is being copied. Here is an example code:cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct Vertex
{
float x, y, z;
Vertex(float x, float y, float z)
: x(x), y(y), z(z)
{}
Vertex(const Vertex& vertex)
: x(vertex.x), y(vertex.y), z(vertex.z)
{
// highlight that our vector is copied
std::cout << "Copied!" << std::endl;
}
};
int main()
{
std::vector<Vertex> vertices;
vertices.push_back(Vertex(1, 2, 3));//line 23
vertices.push_back(Vertex(4, 5, 6));
vertices.push_back(Vertex(4, 5, 6));
std::cin.get();
}
- Running the above code, we get six “Copied” in the console.
Avoid copy result from reallocation
- Once a vector’s capacity is exceeded, it needs to reallocate new memory which involves copying data to a new location, deleting old data, and adding new data. This process can be slow and inefficient, and it is where we begin the optimization process.
- Every time the
push_back()
method is called, the vertices vector is reallocated due to its size not being sufficient. To optimize this, we can call thereserve()
method to specify that the size of the vector should be 3, thereby avoiding unnecessary reallocations.
cpp
1 | ...// omit |
- In the given code, calling
reserve(3)
before adding the elements will optimize the performance by avoiding three unnecessary memory reallocations and copying. - After using the
reserve()
method, we will only get 3 “Copied”.
Avoid copy caused by constructing function
- In the example code, lines 29-30 create a Vertex in the main scope using a constructor, and then copy it to the vector. This is inefficient and can be improved by using the
emplace_back()
method instead.cpp1
2
3vertices.emplace_back(1, 2, 3);
vertices.emplace_back(4, 5, 6);
vertices.emplace_back(4, 5, 6); - The
emplace_back()
method pass parameters list directly to the constructor, avoiding unnecessary copy.
- After applying the optimization mentioned above, rerun the code and you will observe that there are no “Copied” statements being printed in the console.
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Momoyeyu!