Use empty () instead of checking whether size () is empty
For any container C, write down
If (C. Size () = 0 )...
Essentially equivalent to writing
If (C. Empty ())...
This is an example. You may wonder why a constructor is better than another one, especially in fact, the typical Implementation of empty () is an inline function that returns size () whether to return 0.
You should first choose the empty () Construction, and the reason is very simple: For all the standard containers, empty () is a constant time operation, but for some list implementations, size () it takes linear time.
But what causes the list to be so troublesome? Why can't we also provide a constant time size ()? The answer is that there are a lot of things to deal with the list-specific splice. Consider this Code:
List <int> list1;
List <int> list2;
List1.splice (// put
List1.end (), list2, // from the first occurrence of 5
Find (list2.begin (), list2.end (), 5), // The last occurrence of 10
Find (list2.rbegin (), list2.rend (), 10). Base () // moves the part to the end of list1
); // For the called
This Code cannot work unless list2 has a 10 value next to 5, but we assume this is not a problem. Instead, let's focus on this question: how many elements does list1 have after merging? Obviously, the number of list1 elements after merging is equal to the number of list1 elements before merging plus the number of elements merged. But how many elements are merged? That is equal to the number of elements in the intervals defined by find (list2.begin (), list2.end (), 5), find (list2.rbegin (), list2.rend (), 10). Base. OK, how many are there? You cannot know Before traversing this interval and counting it. That is the problem.
Suppose you are responsible for implementing list now. List is not just a common container, it is a standard container, so you know that your class will be widely used. You naturally want your implementation to be more efficient and better. You point out that customers often want to know the number of elements in the list, so you make size () into a constant time operation. Therefore, you need to design the list to always know how many elements are contained.
At the same time, you know that for all standard containers, only list provides the ability to merge elements from one place to another without copying data. Your inference is that many List users will select a special list because it provides efficient merge. They know that merging a region from a list to another list can be completed within a constant time, and you know that they understand this, so you are sure you need to meet their expectations, merge is a member function of constant time.
This leaves you in a dilemma. If size () is a constant time operation, each list member function must update the list size during the operation. Also includes splice (). However, the only way to let splice () Update the size of the list he changed is to calculate the number of elements merged, but doing so will make splice () it is impossible to have the performance of the constant time you want. If you remove the need for splice () to update the size of its modified list, splice () can be a constant time, But size () becomes a linear time operation. In general, it must traverse its entire data structure to know how many elements it contains. Whatever you think about it, some things -- size () or splice () -- must be concession. One or another can be a constant time operation, but not both.
Different list implementations solve this conflict in different ways, depending on their authors who choose to make size () or splice () the most efficient. If you happen to use a list implementation with a constant time higher than the size () of the constant time, calling empty () is better than calling size () because empty () always constant time operation. Even if you are not using this implementation, you may find that you will use this implementation in the future. For example, you may transplant your code to a different platform using different STL implementations, or you may just decide to switch to a different STL implementation on your current platform.
No matter what happens, if you use empty () instead of checking whether the size () is 0, no error will occur. Empty () should be called when you want to know whether the container contains 0 elements ().