C + + container
Basic Usage
Gets the length of the container
Before, we often used sizeof() to obtain the length of the array:
int data[17]; size_t data_size = sizeof(data)/sizeof(data[0]); printf("Size of array: %zu",data_size);
However, using the size() method of the container can obtain the data length more conveniently:
std::array<int,17> data_{}; std::cout<<"Size of array: "<<data_.size()<<std::endl;
Determine whether the container is empty
No standard way of checking if empty
int full_arr[5] = {1,2,3,4}; printf("Array empty: %d",full_arr[0]==NULL);
empty()
std::vector<int> empty_vec_{}; std::cout<<"Array empty: "<<empty_vec_.empty()<<std::endl;
Get last data
If you do not use a container, getting the last element may be out of bounds:
float f_arr[N] = {1.5,2.3}; printf("Last element : %f",f_arr[3]);
Now you can use the back() method directly
std::array<float,2> f_arr_{1.5,2.3}; cout<<"Last element: "<<f_arr_.back()<<endl;
Clear members
clear()
std::vector<char> letters = {'n','a'}; letters.clear();
Of course, you can also use the std::string type
std::string letters{"nacho"}; letters.clear();
When do I use containers?
Here we should ask a rhetorical question, why not apply to containers? Compared with arrays, containers not only make the program easier to read, but also have more methods, such as size(), empty(), front(), and so on. They also support STL algorithm.
Common containers
std::array
Header file: #include < array >
Create an array container: STD:: array < float, 3 > var = {1.0F, 2.0f, 3.0f} to store a series of variables of the same data type.
example
#include<iostream> #include<array> using std::cout; using std::endl; int main(){ std::array<float,3> container_float = {1.1f, 2.2f, 3.3f}; for(const float & element : container_float){ cout<<element<<endl; } cout<<std::boolalpha<<endl; cout<<"Array size: "<< container_float.size()<<endl; cout<<"Array empty: "<<container_float.empty()<<endl; return 0; }
std::vector
The usage of vectors here is similar to that of the previous arrays. The header file #include < vector > is imported. The implementation of vector is Dynamic table, so elements can be added and deleted:
- Clear all data: clear
- Add an element, commonly used in history, VEC push_ Back (value), but VEC is more recommended in C++11 emplace_ Back (value) add element
It is worth noting that vector does not pay attention to the statement of size. We pay more attention to the reserved memory size of a vector, that is, capacity. This is also a direction for us to optimize vector, that is, we should reserve enough memory space to avoid frequent memory applications and releases. The method used is reserve(n), and N is the maximum number of variables expected to be stored.
Case:
Create two vector s. The first one has allocated enough space in advance, and the second one has not allocated enough space. The system will allocate memory automatically
#include<iostream> #include<vector> using std::cout; using std::endl; int main(){ const int N = 100; std::vector<int> v1; cout<<"v1 has been created\ncapacity:"<<v1.capacity()<<" size:"<<v1.size()<<endl; v1.reserve(N); cout<<"After v1.capacity() \ncapacity:"<<v1.capacity()<<" size:"<<v1.size()<<endl; for(int i=0; i<N ; i++){ v1.emplace_back(i); } cout<<"v1 has been filled \ncapacity:"<<v1.capacity()<<" size:"<<v1.size()<<endl; // v2 std::vector<int> v2; cout<<"v2 has been created\ncapacity:"<<v2.capacity()<<" size:"<<v2.size()<<endl; for(int i=0; i<N ; i++){ v2.emplace_back(i); } cout<<"v2 has been filled \ncapacity:"<<v2.capacity()<<" size:"<<v2.size()<<endl; return 0; }
It is not difficult to find from the results:
- The capacity after vector initialization is 0
- If memory is not allocated in advance, it may not only waste time due to frequent memory applications, but also waste memory.
application
Open3D::PointCloud
std::map
mapping type
case
#include<iostream> #include<map> #include<string> int main(){ std::map<int,std::string> students; students.emplace(3,"xiaoming"); //[3] students.emplace(1,"xiaohong"); //[1] students.emplace(2,"xiaohong"); //[2] for(const auto& [id,name] : students){ std::cout<<"id:"<<id<<" name:"<<name<<std::endl; } std::cout<<"size:"<<students.size()<<std::endl; return 0; }
Output results
It can be seen that the key value pairs here have been reordered.
std::unordered_map
The sorting of this method is realized through the hash table, so the key should be processed by the hash function, such as integer and string. Only change the map to unordered_map. The above cases run in an unordered list, as shown below, and are randomly arranged according to the hash function
At present, all built-in types have implemented hash functions
Iterating over maps
In the previous idea, we can use the following method to iterate the map
for(const auto& kv : m){ const auto& key = kv.first; const auto& value = kv.second; // Do work }
In C++17, we can abbreviate it to the following form
for(const auto& [key,value] : m){ // Do work }
Much More about container
C + + iterators
Suppose we need to traverse each element of the output vector, array and list. In the past, we used to create a function for each type, but this function can be realized more concisely by overloading with iterators:
template<typename Iterator> void print_it(Iterator begin, Iterator end){ for(Iterator it = begin; it!=end; it++){ std::cout<<*it<<" "; } std::cout<<std::endl; }
It can be seen that the iterator in C + + acts as the glue between the standard library algorithm and the data structure, minimizing the dependence of the algorithm on the operated data structure.
STL is to obtain the elements of the container by using the iterator, * iter points to the element of the current position, + + points to the pointer of the next position, or through = == Compare with <.
Containers also provide different iterators, such as begin, end, and so on.
STL Algorithms
STL has about 80 kinds of algorithms, which are called through #include < algorithm >, so as to avoid making the wheel repeatedly.
The following are the commonly used STL algorithms
-
std::sort(s.begin(),s.end()), in ascending order by default
-
std::find(v.begin(),v.end(),n1)
auto result = std::find(v.begin(),v.end(),n1); if(result!=std::end(v)){ cout<<"successful"; } else{ cout<<"false"; }
-
std::fill(v.begin(),v.end(),n1)
-
std::count(v.begin(),v.end(),n1)
-
std::count_if, the count that meets the condition
inline bool div_by_3(int i){return i%3==0;} int main(){ std::vector<int> v{1,2,3,4,4,5,6,6}; int result = std::count_if }
-
std::for_each(begin,end,function_handle)
#include<vector> #include<iostream> #include<algorithm> using std::cout; using std::endl; int main(){ // Using std::for_each outputs each element of the vector std::vector<int> v1{1,2,3,4,5,6}; //Anonymous function auto print = [](const int a){cout<<a<<" "; }; std::for_each(v1.begin(),v1.end(),print); return 0; }
-
std::all_off() to judge whether all members meet the conditions
inline bool even(int i){return i%2==0;}; int main(){ std::vector<int> v{2,4}; bool all_is_even = all_of(v.begin(),v.end(),even); }
-
std::rotate(), rotate the member
int main () { std :: vector <int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cout << "before rotate: "; Print(v); std :: rotate(v.begin (), v.begin () + 2, v.end ()); cout << "after rotate: "; Print(v); } //before rotate: 1 2 3 4 5 6 7 8 9 10 //after rotate: 3 4 5 6 7 8 9 10 1
-
std::transform(), convert the members of one container into the members of another container one by one
#include<iostream> #include<string> #include<algorithm> using std::cout; using std::endl; auto UpperCase(char c){return std::toupper(c);} int main(){ const std::string s("hello"); std::string S(s); std::transform(s.begin(),s.end(),S.begin(),UpperCase); cout<<s<<endl; cout<<S<<endl; return 0; } // output // hello // HELLO
-
std::accumulate(), which can realize accumulation, multiplication and other operations
int main () { std :: vector <int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int sum = std :: accumulate (v.begin (), v.end (), 0); int product = std :: accumulate (v.begin (), v.end (), 1, std :: multiplies ()); cout << "Sum : " << sum << endl; cout << "Product: " << product << endl; } // Sum : 55 // Product: 3628800
-
std::min_element()
int main () { std :: vector <int> v{3, 1, 4, 1, 0, 5, 9}; auto result = std :: min_element (v.begin (), v.end ()); auto min_location = std :: distance(v.begin (), result); cout << "min at: " << min_location << endl; } // min at: 4
-
std::minmax_element()
int main () { using std :: minmax_element ; auto v = {3, 9, 1, 4, 2, 5, 9}; auto [min , max] = minmax_element (begin(v), end(v)); cout << "min = " << *min << endl; cout << "max = " << *max << endl; } // min = 1 // max = 9
-
std::clamp()
int main () { // value should be between [kMin ,kMax] const double kMax = 1.0F; const double kMin = 0.0F; cout << std :: clamp (0.5 , kMin , kMax) << endl; cout << std :: clamp (1.1 , kMin , kMax) << endl; cout << std :: clamp (0.1 , kMin , kMax) << endl; cout << std :: clamp (-2.1, kMin , kMax) << endl; } // 0.5 // 1 // 0.1 // 0
-
std::sample()
int main () { std :: string in = "C++ is cool", out; auto rnd_dev = std :: mt19937{ random_device {}() }; const int kNLetters = 5; std :: sample(in.begin (), in.end (), std :: back_inserter (out), kNLetters , rnd_dev); cout << "from : " << in << endl; cout << "sample: " << out << endl; } // from : C++ is cool // sample: C++cl
Of this class Slides link and Course address.