Why are the standard containers so slow?

Source: Internet
Author: User
They are not. Probably "compared to what? "Is a more useful answer. When people complain about standard-library container performance, I usually find one of three genuine problems (or one of the following myths and red herrings ):

  • I suffer copy overhead
  • I suffer slow speed for Lookup tables
  • My hand-coded (intrusive) lists are much faster than STD: List

Before trying to optimize, consider if you have a genuine performance problem. In most of cases sent to me, the performance problem is theoretical or imaginary: first measure, then optimise only if needed.

Let's look at those problems in turn. often, a vector <x> is slower than somebody's specialized my_container <x> because my_container <x> is implemented as a container of pointers to X. the standard containers hold copies of values, and copy a value when you put it into the container. this is essential unbeatable for small values, but can be quite unsuitable for huge objects:

vector<int> vi;vector<Image> vim;// ...int i = 7;Image im("portrait.jpg");// initialize image from file// ...vi.push_back(i);// put (a copy of) i into vivim.push_back(im);// put (a copy of) im into vim

Now, if portrait.jpg is a couple of megabytes and image has value semantics (I. E ., copy assignment and copy construction make copies) Then vim. push_back (IM) will indeed be expensive. but -- as the saying goes -- if it hurts so much, just don't do it. instead, either use a container of handles or a containers of pointers. for example, if image had reference semantics, the code above wocould incur only the cost of a copy constructor call, which wocould be trivial compared to most image manipulation operators. if some class, say image again, does have copy semantics for good reasons, a container of pointers is often a reasonable solution:

vector<int> vi;vector<Image*> vim;// ...Image im("portrait.jpg");// initialize image from file// ...vi.push_back(7);// put (a copy of) 7 into vivim.push_back(&im);// put (a copy of) &im into vim

Naturally, if you use pointers, you have to think about resource management, but containers of pointers can themselves be either tive and cheap resource handles (often, you need a container with a destructor for deleting the "owned" objects ).

The second frequently occuring genuine performance problem is the use of a map for a large number of (string, x) pairs. maps are fine for relatively small containers (say a few hundred or few thousand elements -- access to an element of a map of 10000 elements costs about 9 comparisons), where less-than is cheap, and where no good hash-function can be constructed. if you have lots of strings and a good hash function, use a hash table. the unordered_map from the standard committee's tecnical report is now widely available and is far better than most people's homebrew.

Sometimes, you can speed up things by using (const char *, x) pairs rather than (string, x) pairs, but remember that <doesn't do lexicographical comparison for C-style strings. also, if X is large, you may have the copy problem also (solve it in one of the usual ways ).

Intrusive lists can be really fast. however, consider whether you need a list at all: a vector is more compact and is therefore smaller and faster in your cases-even when you do inserts and erases. for example, if you logically have a list of a few integer elements, a vector is significantly faster than a list (any list ). also, intrusive lists cannot hold built-in types directly (an int does not have a link member ). so, assume that you really need a list and that you can supply a link field for every element type. the standard-library list by default performs an allocation followed by a copy for each operation inserting an element (and a deallocation for each operation removing an element ). for STD: list with the default Allocator, this can be significant. for small elements where the copy overhead is not significant, consider using an optimized allocator. use a hand-crafted intrusive lists only where a list and the last ounce of performance is needed.

People sometimes worry about the cost of STD: vector growing incrementally. I used to worry about that and used reserve () to optimize the growth. after measuring my code and repeatedly having trouble finding the performance benefits of reserve () in real programs, I stopped using it validation t where it is needed to avoid iterator invalidation (a rare case in my code ). again: measure before you optimize.

 

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.