Book-en-us
- Preface
- Chapter 01: Towards Modern C++
- Chapter 02: Language Usability Enhancements
- Chapter 03: Language Runtime Enhancements
- Chapter 04 Containers
- Chapter 05 Smart Pointers and Memory Management
- Chapter 06 Regular Expression
- Chapter 07 Parallelism and Concurrency
- Chapter 08 File System
- Chapter 09 Minor Features
- Chapter 10 Outlook: Introduction of C++20
- Appendix 1: Further Study Materials
- Appendix 2: Modern C++ Best Practices
Chapter 04 Containers
4.1 Linear Container
std::array
When you see this container, you will have this problem:
- Why introduce
std::array
instead ofstd::vector
directly? - Already have a traditional array, why use
std::array
?
First, answer the first question. Unlike std::vector
, the size of the std::array
object is fixed. If the container size is fixed, then the std::array
container can be used first.
Also, since std::vector
is automatically expanded, when a large amount of data is stored, and the container is deleted,
The container does not automatically return the corresponding memory of the deleted element. In this case, you need to manually run shrink_to_fit()
to release this part of the memory.
std::vector<int> v; |
The second problem is much simpler. Using std::array
can make the code more "modern" and encapsulate some manipulation functions, such as getting the array size and checking if it is not empty, and also using the standard friendly. Container algorithms in the library, such as std::sort
.
Using std::array
is as simple as specifying its type and size:
std::array<int, 4> arr = {1, 2, 3, 4}; |
When we started using std::array
, it was inevitable that we would encounter a C-style compatible interface. There are three ways to do this:
void foo(int *p, int len) { |
std::forward_list
std::forward_list
is a list container, and the usage is similar to std::list
, so we don't spend a lot of time introducing it.
Need to know is that, unlike the implementation of the doubly linked list of std::list
, std::forward_list
is implemented using a singly linked list.
Provides element insertion of O(1)
complexity, does not support fast random access (this is also a feature of linked lists),
It is also the only container in the standard library container that does not provide the size()
method. Has a higher space utilization than std::list
when bidirectional iteration is not required.
4.2 Unordered Container
We are already familiar with the ordered container std::map
/std::set
in traditional C++. These elements are internally implemented by red-black trees.
The average complexity of inserts and searches is O(log(size))
. When inserting an element, the element size is compared according to the <
operator and the element is determined to be the same.
And select the appropriate location to insert into the container. When traversing the elements in this container, the output will be traversed one by one in the order of the <
operator.
The elements in the unordered container are not sorted, and the internals is implemented by the Hash table. The average complexity of inserting and searching for elements is O(constant)
,
Significant performance gains can be achieved without concern for the order of the elements inside the container.
C++11 introduces two unordered containers: std::unordered_map
/std::unordered_multimap
and
std::unordered_set
/std::unordered_multiset
.
Their usage is basically similar to the original std::map
/std::multimap
/std::set
/set::multiset
Since these containers are already familiar to us, we will not compare them one by one. Let's compare std::map
and std::unordered_map
directly:
#include <iostream> |
The final output is:
std::unordered_map |
4.3 Tuples
Programmers who have known Python should be aware of the concept of tuples. Looking at the containers in traditional C++, except for std::pair
there seems to be no ready-made structure to store different types of data (usually we will define the structure ourselves).
But the flaw of std::pair
is obvious, only two elements can be saved.
Basic Operations
There are three core functions for the use of tuples:
std::make_tuple
: construct tuplestd::get
: Get the value of a position in the tuplestd::tie
: tuple unpacking
#include <tuple> |
std::get
In addition to using constants to get tuple objects, C++14 adds usage types to get objects in tuples:
std::tuple<std::string, double, double, int> t("123", 4.5, 6.7, 8); |
Runtime Indexing
If you think about it, you might find the problem with the above code. std::get<>
depends on a compile-time constant, so the following is not legal:
int index = 1; |
So what do you do? The answer is to use std::variant<>
(introduced by C++ 17) to provide type template parameters for variant<>
You can have a variant<>
to accommodate several types of variables provided (in other languages, such as Python/JavaScript, etc., as dynamic types):
#include <variant> |
So we can:
int i = 1; |
Merge and Iteration
Another common requirement is to merge two tuples, which can be done with std::tuple_cat
:
auto new_tuple = std::tuple_cat(get_student(1), std::move(t)); |
You can immediately see how quickly you can traverse a tuple? But we just introduced how to index a tuple
by a very number at runtime, then the traversal becomes simpler.
First, we need to know the length of a tuple, which can:
template <typename T> |
This will iterate over the tuple:
for(int i = 0; i != tuple_len(new_tuple); ++i) |
Conclusion
This chapter briefly introduces the new containers in modern C++. Their usage is similar to that of the existing containers in C++. It is relatively simple, and you can choose the containers you need to use according to the actual scene, to get better performance.
Although std::tuple
is effective, the standard library provides limited functionality and there is no way to meet the requirements of runtime indexing and iteration. Fortunately, we have other methods that we can implement on our own.
Changkun Ou © 2016-2024. The book is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0, code is open sourced under the MIT License.
If you like the book, you could donate the author.