Memory and efficiency in STL

Source: Internet
Author: User

Memory and efficiency in STL

1. Use the reserve () function to set the size of the capacity in advance to avoid multiple capacity expansion operations resulting in inefficiency.

One of the most admirable features about STL containers is that they can automatically grow to accommodate the data you put in as long as they don't exceed their maximum size. (To know this maximum value, just call the member function called Max_size.) For vectors and strings, if more space is needed, it grows in size like realloc thought.

The vector container supports random access, so in order to improve efficiency, it is implemented internally using dynamic arrays .

When you request a specific size by reserve (), it always increases its internal buffer by exponential bounds.

When adding elements such as insert or push_back, if the memory of the dynamic array is not enough, it is necessary to dynamically reassign the new memory area of the current size 1.5~2 times, and then copy the contents of the original array into the past. Therefore, in general, its access speed is the same as the general array, only when the reallocation occurs, its performance will be degraded. As the above code tells you.

In the case of pop_back operations, the capacity does not decrease due to the decrease in the elements in the vector container, but also maintains the size before the operation. For vector containers, if there is a large amount of data to be push_back, the reserve () function should be used to set its capacity in advance, otherwise there will be many sub-capacity expansion operations, resulting in inefficient.

The reserve () member function allows you to minimize the number of re-allocations that must be made, thus avoiding the overhead of true allocations and invalidation of iterators/pointers/references. But before I explain why reserve can do that, let me briefly describe some of the four related member functions that are sometimes confusing.

In a standard container, only the vector and string provide all of these functions.

(1) Size () tells you how many elements are in the container. It does not tell you how much memory the container allocates for the elements it holds.
(2) capacity () tells you how many elements the container can hold in the memory it has allocated . That's how many elements a container can hold in that memory, rather than how many elements it can hold.

If you want to know how much memory is not occupied in a vector or string, you must subtract size () from capacity (). If size and capacity return the same value, there is no space left in the container, and the next insertion (via insert or push_back, etc.) will cause the above redistribution step.
(3) Resize (container::size_type N) forcibly changes the container to accommodate n elements . after calling resize, size will return N. If n is less than the current size, the element at the end of the container is destroyed . If n is greater than the current size, the new default constructed element is added to the container trailer. If n is greater than the current capacity, redistribution occurs before the element is added.
(4) reserve (Container::size_type N) forces the container to change its capacity to at least N, providing n is not less than the current size . This generally forces a redistribution, as capacity needs to be increased. (if n is less than the current capacity, the vector ignores it, and the call does nothing, and the string may reduce its capacity to size () and the large number in N, but the size of the string does not change.)

In my experience, using the reserve to trim excess capacity from a string is generally not as good as using the "swap technique", which is the subject of clause 17. )

This profile indicates that redistribution occurs whenever there are elements that need to be inserted and the capacity of the container is insufficient (including the raw memory allocations and recoveries they maintain, the copying and destruction of objects and the invalidation of iterators, pointers, and references).

Therefore, the key to avoid redistribution is to use reserve as soon as possible to set the container capacity is large enough, preferably after the container is constructed immediately .

For example, suppose you want to create a vector<int> that holds 1-1000 values. Instead of using reserve, you can do it like this:

vector<int> v;  for (int1, ++i) v.push_back (i);

In most STL implementations, this code will cause 2 to 10 reallocation during the loop. (10 This number is nothing strange.) Remember that vectors tend to double the capacity at the time of redistribution, and 1000 is approximately equal to 210. )

To change the code to use reserve, we get this:

vector<int> v;v.reserve (+);  for (int1, + +i) v.push_back (i); this does not occur in the loop redistribution. 

The relationship between size and capacity allows us to predict when the insertion will cause a vector or string to be reassigned, and to predict when the insertion will invalidate iterators, pointers, and references in the container. For example, given this code,

string s; .. if (S.size () < s.capacity ()) {S.push_back ('x');}

  The push_back call does not invalidate the iterator , pointer , or reference that points to the string, because the capacity of the string is guaranteed to be greater than its size. If Push_back is not executed, the code makes an insert anywhere in the string, and we can still guarantee that no redistribution occurs during the insertion, but consistent with the general rule that the iterator fails when the string is inserted, all the the iterator/pointer/reference at the insertion position to the end of string will be invalidated.

Back to the main thrust of this article, there are usually two cases where the reserve is used to avoid unnecessary redistribution.

(1) The first available case is when you know exactly or about how many elements will eventually appear in the container. In that case, just like the vector code above, you just reserve an appropriate amount of space in advance.

(2) The second case is to keep the maximum space you may need , and then, once you've added all the data, trim out any excess capacity .

2. Use "switching technique" to trim vector excess space/memory

There is a way to reduce it from the once-largest capacity to the capacity it now needs.

This way of reducing capacity is often referred to as " Shrinking to Fit" (Shrink to fit). This method requires only one statement:vector<int> (IVEC). Swap (Ivec).

The expression vector<int> (Ivec) establishes a temporary vector, which is a copy of the Ivec: thecopy constructor of the vector does the work . However, the vector's copy constructor allocates only the memory required for the copied elements, so this temporary vector has no extra capacity. Then we let the temporary vector and the Ivec exchange data, when we finished, Ivec only the temporary variable of the trimmed capacity, and this temporary variable holds the unused excess capacity that was once in the Ivec. Here (at the end of this statement), the temporary vector is destroyed, so the memory used by the previous Ivec is freed and shrunk to fit .

3. Use the Swap method to forcibly release the memory of the STL vector

Template <classT>voidClearvector (vector<t>&v) {Vector<T>vttemp; Vttemp.swap (v);} such as Vector<int>v; Nums.push_back (1); Nums.push_back (3); Nums.push_back (2); Nums.push_back (4); Vector<int>(). Swap (v);/*or V.swap (vector<int> ());*//*or {std::vector<int> tmp = V;   V.swap (TMP); };
the brace {} is auto-destructor when tmp exits {} */Because the scope of the temporary variable was exited

4. Vector Memory management behavior test for member functions

The vector of C + + STL is very widely used, but the management model of its memory has been a lot of guesses, the following example code test to understand its memory management method , the test code is as follows:

#include <iostream>#include<vector>using namespacestd;intmain () {vector<int>Ivec;cout<<"the container size is:"<< ivec.size () <<Endl; //Temporary data items are saved, but there are 1 capacity cout<<"the container capacity is:"<< ivec.capacity () << Endl;//1 elements with a container capacity of 1Ivec.push_back (1); cout<<"the container size is:"<< ivec.size () <<Endl; //There are 1 data items cout<<"the container capacity is:"<< ivec.capacity () << Endl;//2 elements with a container capacity of 2,(size = = capacity, capacity range capacity X2) Ivec.push_back (2); cout<<"the container size is:"<< ivec.size () <<Endl; //There are 2 data items cout<<"the container capacity is:"<< ivec.capacity () << Endl;//3 elements with a container capacity of 4Ivec.push_back (3); cout<<"the container size is:"<< ivec.size () <<Endl; //There are 3 data items cout<<"the container capacity is:"<< ivec.capacity () << Endl;//4 Elements with a container capacity of 4,(3 + 1 = = 4, i.e. size = = capacity, capacity range capacity X2) Ivec.push_back (4); Ivec.push_back (5); cout<<"the container size is:"<< ivec.size () <<Endl;cout<<"the container capacity is:"<< ivec.capacity () << Endl;//5 Elements with a container capacity of 8Ivec.push_back (6); cout<<"the container size is:"<< ivec.size () <<Endl;cout<<"the container capacity is:"<< ivec.capacity () << Endl;//6 elements with a container capacity of 8Ivec.push_back (7); cout<<"the container size is:"<< ivec.size () <<Endl;cout<<"the container capacity is:"<< ivec.capacity () << Endl;//7 elements with a container capacity of 8Ivec.push_back (8); cout<<"the container size is:"<< ivec.size () <<Endl;cout<<"the container capacity is:"<< ivec.capacity () << Endl;//8 elements with a container capacity of 8 (size = = capacity, capacity range capacity X2)  Ivec.push_back (9); cout<<"the container size is:"<< ivec.size () <<Endl;cout<<"the container capacity is:"<< ivec.capacity () << Endl;//9 elements with a container capacity of/*VS2005/8 capacity growth is not doubled, such as 9 element capacity 9 10 element capacity*//*test The Special Swap Swap () in the effective STL*/cout<<"the size of the current vector is:"<< ivec.size () <<Endl;cout<<"the capacity of the current vector is:"<< ivec.capacity () <<Endl;vector<int>(IVEC). Swap (IVEC); cout<<"The size of the temporary vector<int> object is:"<< (vector<int> (IVEC)). Size () <<Endl;cout<<"The capacity of the temporary vector<int> object is:"<< (vector<int> (IVEC)). Capacity () <<Endl;cout<<"after swapping, the size of the current vector is:"<< ivec.size () <<Endl;cout<<"after swapping, the current vector's capacity is:"<< ivec.capacity () <<Endl;return 0;}

5. Other member functions of the vector

c.assign (beg,end) assigns the data in the [beg; end] Interval to C. C.assign (N,elem) assigns a copy of n elem to C. c.at (IDX) returns the index IDX refers to the data, if the IDX is out of bounds, throws Out_of_range. C.back () returns the last data without checking to see if the data exists. C.front () returns a data back to the ground. Get_allocator uses the constructor to return a copy. C.rbegin () returns the first data for a reverse queue . C.rend () returns the next position of the last data in a reverse queue. C. ~ Vector <Elem>

Memory and efficiency in STL

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.