Vector avoids frequent memory allocation and frees vector memory manually

Source: Internet
Author: User

Original link: http://blog.csdn.net/cws1214/article/details/47984053

1. Avoid frequent redistribution

One of the most admirable features of STL containers is that they can automatically grow enough to accommodate the data you put in, as long as they are not larger than their maximum size. (To know the maximum value, just call the member function named Max_size.) )

For vectors and strings, if more space is needed, the size is increased by a similar realloc thought. This realloc-like operation has four parts: allocate a new block of memory, which has a multiple of the current capacity of the container. In most implementations, the capacity of the vector and string increases by 2 each time. That is, when the container has to be expanded, its capacity doubles every time. Copy all the elements from the container's old memory to its new memory. Destroys objects in old memory. Reclaim old memory.

Given all the allocations, recycling, copying and deconstruction, you should know that those steps are expensive. Of course, you don't want to execute them more frequently than you have to. If this doesn't give you a blow, then maybe when you think about every time these steps happen, all the iterators, pointers, and references that point to vectors or string will fail, and it'll hit you. This means that simply inserting an element into a vector or string action requires updating other data structures that use an iterator, pointer, or reference that points to vectors or strings.

The reserve member function allows you to minimize the number of times that you have to reassign, so you can avoid the overhead of true allocations and the failure of iterators/pointers/references. But before I explain why reserve can do that, let me briefly introduce the four related member functions that are sometimes confusing. In a standard container, only vectors and strings provide all of these functions. Size () tells you how many elements there are in the container. It does not tell you how much memory the container allocates for the elements it holds. Capacity () tells you how many elements the container can hold in the memory it has already allocated. That's how many elements a container can hold in that block of memory, not 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 the size () from the 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.) causes the reallocation step above. Resize (container::size_type N) forces the container to accommodate n elements instead. When resize is invoked, the size returns N. If n is less than the current size, the elements of the container's tail are destroyed. If n is greater than the current size, the new default constructed element is added to the container's tail. If n is greater than the current capacity, redistribution occurs before the element is joined. Reserve (Container::size_type N) forces the container to change its capacity to at least N, providing n not less than the current size. This generally forces a reallocation because the capacity needs to be increased. (if n is less than the current capacity, the vector ignores it, the call does nothing, and a string may reduce its capacity to the size () and the number of large n, but the string does not have a change.) In my experience, using 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. ) [1]

This profile represents the redistribution (including the raw memory allocations and recoveries that they maintain, the invalidation of objects ' copies and destructors, pointers, and references) whenever there are elements that need to be inserted and the container's capacity is low. So, the key to avoiding redistribution is to use reserve to set the capacity of the container as quickly as possible, preferably immediately after the container is constructed.

For example, suppose you want to create a vector<int> that holds a value of 1-1000. Without using reserve, you can do it like this: Vector<int> V; for (int i = 1; I <= 1000; ++i) v.push_back (i);

In most STL implementations, this code will cause 2 to 10 redistribution during the loop. (10 This number is nothing strange.) Remember that vectors usually double the capacity when redistribution occurs, and 1000 is about 210. )

Change the code to use reserve, we get this: Vector<int> V; V.reserve (1000); for (int i = 1; I <= 1000; ++i) v.push_back (i);

This does not occur in the loop.

The relationship between size and capacity allows us to predict when the insertion will cause a vector or string to perform redistribution, and that it is possible to predict when the insertion will invalidate the iterator, pointer, and reference in the container. For example, give this piece of code, string s; ... if (s.size () < s.capacity ()) {s.push_back (' x ');}

A push_back call does not invalidate an iterator, pointer, or reference in this string because the capacity of a string is guaranteed to be greater than its size. If it is not executing push_back, the code makes an insert at any point in string, we can still guarantee that no redistribution will occur during the insertion, but it is consistent with the general rule that the iterator fails when the string is inserted. All iterators/pointers/references from the insertion position to the end of a string are invalidated.

Back to the main thrust of this article, there are usually two situations in which reserve is used to avoid unnecessary redistribution. The first available scenario is when you know exactly or approximately how many elements will eventually appear in the container. In that case, like the vector code above, you just reserve the right amount of space in advance. The second scenario is to keep the maximum space you may need, and then, once you've added all the data, trim any excess capacity.



2. Free vector memory

The blogger uses a vector to store some data, but discovers that the memory is not released after the execution of Clear () and then suspects that a memory leak has been generated. Then someone responded:

"Vector clear does not affect capacity, you should swap an empty vector." ”

At first you didn't know what the respondents were saying, so searching for vector swap clear on Google found that a similar problem had occurred and offered some solutions.

Originally such a problem in the "effective STL" in "clause 17" has been pointed out

When vector, string inserts data heavily, even if a large amount of data is deleted (or all of them are deleted, clear) does not change the container's capacity (capacity), it still occupies memory. To avoid this, we should try to change the capacity of the container to match the current data as little as possible (shrink to fit)

The solution given in the effective STL is:

Vector<type> v; //.... Here add a lot of elements to V//....  This deletes many of the elements in V vector<type> (v). Swap (v); At this time V's capacity has been as much as possible with the number of elements it currently contains//for string it may be as follows string (s). Swap (s);

The first to create a temporary copy is consistent with the original vector, it should be noted that at this time the copy of its capacity is as small as possible to meet the required data. The copy is then exchanged with the original vector v. All right. At this point, after the exchange is performed, the temporary variable is destroyed and the memory is freed. At this time V is the original temporary copy, and the temporary copy after the exchange is a very large capacity vector (but has been destroyed)

To prove this, I wrote a program as follows:

#include  <iostream>  #include  <vector>     using namespace  std;     vector <string> v;  char ch;     int main   ()   {         for (int i=0; i<1000000; i++)           v.push_back ("ABCDEFGHIJKLMN");       cin >> ch;      //  Check memory at this time   occupy 54m          v.clear ();      cin >> ch;       //  Check again at this time,  still occupy 54m         cout <<  "Vector     Capacity for " << v.capacity ()  << endl;      //   At this time the capacity is  1048576         vector<string> (v). Swap (v);          cout <<  "vector    capacity for"  << v.capacity ()   << endl;      //  capacity at this time is 0      cin >>  ch;      //  Check memory, release  10M+  that is data memory        return 0; }  Summary

From this thing, your understanding of the STL is also very not normal to the vector of the removal of the know how to use the Clear method.

On the other hand, there is also some understanding of the design of the STL, the vector after the creation of the actual capacity of vectors will generally be larger than the data, it should be to avoid excessive reallocation of memory bar.

Of course, the above method frees up memory, but it also increases the time consuming to copy data. However, the general need to readjust the capacity of the case is the vector itself less than the case, so time consumption can be negligible.

Therefore, it is recommended that you change the call clear () to swap ().

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.