C ++ STL learning notes

Source: Internet
Author: User

#. String suggestion

The convenience of using string is unnecessary. Here we should emphasize the security of string.
 
String is not omnipotent. If you need to process strings frequently in a large project and may be multi-threaded, you must be careful (of course, be careful when using any STL container under multiple threads ).

The implementation and efficiency of string are not necessarily what you think. If you are concerned about a large number of string operations and their efficiency, you have two options: first, you can look at the Source Code implemented by string in the STL version you are using. Another option is to write a class that only provides the functions you need.

The c_str () function of string is used to obtain a C-language string, and its returned pointer cannot modify its space. In addition, a new pointer is obtained after the next call.

The string pointer returned by the data () function of the string will not end with '\ 0', and cannot be ignored.
For the c_str () data () function, the returned array is owned by the string itself and cannot be modified. The reason is that many strings adopt the reference mechanism during implementation. That is to say, several strings may use the same character storage space. And you cannot use sizeof (string) to view its size.

Use operators as much as possible to make the program easier to understand (especially for script programmers ).

The find () function returns a size_type type. The return value is generally the position of the string to be found. If not, the return value is string: NPOs. Note that for comparison with string: NPOs, you must use string: size_type instead of Int or unsigned Int.

#. Sort suggestions

Sort by default from small to large

1. to sort the vector, String, deque, or array containers in full order, you can select sort or stable_sort;

2. If you only need to obtain the top n elements in the vector, String, deque, or array container, partial_sort is the first choice for partial sorting.
Example: First Five: partial_sort (vect. Begin (), vect. Begin () + 5, vect. End ());

3. for a vector, String, deque, or array container, you need to find the element at the nth position or you need to obtain the internal order of Top N, which is irrelevant to Top N, nth_element is ideal.
For example, find the position nth_element (vect. Begin (), vect. Begin () + 4, vect. End () at 5th. // note that it is begin () + 4

Partial_sort () and nth_element () both put the 5 smallest ones in front.

4. If you want to separate elements that meet or do not meet a certain condition from the standard sequence container or array, you 'd better use partition or stable_partition.
For example: student exam ("pass", 60); stable_partition (vect. Begin (), vect. End (), bind2nd (less <student> (), exam ));

5. If you use the list container, you can directly use the partition and stable_partition algorithms. You can use list: sort to replace sort and stable_sort for sorting. If you want to obtain the sorting effect of partial_sort or nth_element, you must use it indirectly.

6. the sort, stable_sort, partial_sort, and nth_element algorithms all need to take the random iterator (random access iterators) as parameters. Therefore, these algorithms can only be used in containers such as vector, String, deque, and array, for standard associated containers such as map, set, multimap, and Multiset, these algorithms are necessary. The comparison functions of these containers keep all elements in the container in an orderly arrangement.

7. for the container list, it seems that these sorting algorithms can be used, but they are also unavailable (the iterator type is not a random iterator ), however, you can use the sort function sort that comes with the list function as needed (the interesting thing is that the list: sort function works the same as a "stable" sort function ).
To use partial_sort or nth_element for a list container, you can only use:
Method (1): copy the elements in the list to a container with a random iterator, and then use these algorithms;
Method (2): generate a container containing list: iterator, sort the list: iterator in the container directly, and then obtain the elements indicated by list: iterator;
Method (3): use an ordered container containing the iterator and repeatedly connect the elements in the list to the location you want to connect.

The behavior of List member functions is often different from that of their brothers. To delete an object from a container, call the remove, remove_if, and unique algorithms, and then call erase to delete the object. However, remove, remove_if, and unique of the list delete the object. The sort algorithm cannot be used for list, but the list can call its own sort member function.

8. Partition and stable_partition are different from sort, stable_sort, partial_sort, and nth_element. They only need two-way iterators. Therefore, partition and stable_partition can be used on any standard sequence iterator.

9. Time and space complexity: stable_sort> sort> partial_sort> nth_element> stable_partition> Partition

#. Delete a specific value from the container

1. If the container is a vector string deque, erase and remove are used in the following ways:
C. Erase (remove (C. Begin (), C. End (), value), C. End ())
Remove cannot delete an element because it cannot. If you want to delete an element, you need to connect erase to remove it.
2. If the container is list, use list: Remove (LS. Remove (value ))
3. If the container is an associated container, use erase to delete the value that meets a specific condition in the container: C. Erase (C. Begin ())
1. If the container is a vector string deque, use erase and remove_if.
2. If the container is list, use list: remove_if
3. If the container is associated with a container, use remove_copy_if and swap, or write a loop to traverse the container element and send the iterator to erase.

Loop traversal to delete values in a container:

// The ordered container cyclically traverses the delete value of the container element:
For (vector <int >:: iterator I = C. Begin (); I! = C. End ();)
If (condition (* I) I = C. Erase (I );
Else ++ I;

// Associate the container to traverse the deleted Value of the container element cyclically:
For (Map <int, int >:: iterator I = C. Begin (); I! = C. End ();)
If (condition (* I) c. Erase (I ++ );
Else ++ I;
The erase (I) of the associated container returns the number of deleted elements. Here, only the Deleted Values are concerned.

#. Iterator failure

Vector:
1. When an element is inserted (push_back), The iterator returned by the end operation is definitely invalid.
2. When an element is inserted (push_back), the return value of capacity is different from that before the element is inserted. Then, the entire container needs to be reloaded, And the iterator returned by the begin and end operations will become invalid.
3. After the delete operation (erase, pop_back) is performed, the iterator pointing to the delete vertex becomes invalid. The iterator pointing to the element after the delete vertex also becomes invalid.

Deque iterator failure:
1. inserting elements in the deque container header (push_front) or tail (push_back) will not invalidate any iterator.
2. Deleting an element in its header (pop_front) or tail (pop_back) only invalidates the iterator pointing to the deleted element.
3. insert and delete operations at any other location of the deque container will invalidate all iterators pointing to the container element.

LIST/set/Map
1. Upon deletion, the iterator pointing to the deleted node becomes invalid.

The resize operation may invalidate the iterator. The resize operation on the vector or deque container may invalidate all its iterators.
Do not store the iterator returned by the end operation. Adding or deleting deque or elements in the vector container will invalidate the stored end iterator.
When an out-of-bounds subscript is used, or the front or back function of an empty container is called, serious errors may occur to the program.
The assignment and assign operations invalidate all iterators of the left operand container. The swap operation does not invalidate the iterator. After the swap operation is completed, the iterator still points to the same element even though the exchanged elements are already stored in another container.
Because the assign operation first deletes all elements originally stored in the container, the iterator passed to the assign function cannot point to the elements in the container that calls the function.

Only applicable to iterator operations of vector and deque containers: ITER + N, ITER-N, iter1 + = iter2, >,>=, <,<=
The list container iterator neither supports arithmetic operations (addition or subtraction) nor relational operations (<=, <, >=,> ), it only provides pre-and post-auto-increment, auto-subtraction, and equal (unequal) operations.

#. Use the swap technique to clear excess capacity

Class contestant {....}
Vector <contestant> V;
... // Is V bigger and then delete part
Vector <contestant> (V). Swap (V); // "contract to fit" on V (V. Size () = V. Capacity ())
Vector <contestant> (). Swap (V); // clear V and minimize its capacity

String S;
... // Is the size of S, and then the part is deleted.
String (s). Swap (s); // "contract to fit" on S"
String (). Swap (s); // clears S and minimizes its capacity

#. Specify the comparison type (not a comparison function) for the containers associated with the pointer)

Set <string *> SSP; // create a container associated with the pointer. The container is sorted by the pointer value. Therefore, the string is not output in alphabetical order.

Struct stringless: Public binary_function <const string *, const string *, bool>
{
Bool operator () (const string * ps1, const string * PS2) const
{
Return * PS1 <* PS2;
}
};
Typedef set <string *, stringless> stringptrset;
Stringptrset SSP;

Or:
Struct dereferenceless
{
Template <typename ptrtype>
Bool operator () (ptrtype P1, ptrtype P2) const
{
Return * P1 <* P2;
}
};
Set <string *, dereferenceless> SSP;
If there is a smart pointer or an iterator associated container, you must also specify a "comparison type" for it"

#. Usage of pai_range

Typedef vector <string >:: iterator Vit;
Typedef pair <VIT, Vit> vitpair;
Sort (SVEC. Begin (), SVEC. End ());
Vitpair Vp = pai_range (SVEC. Begin (), SVEC. End (), "AAA ");
If (VP. First! = VP. Second)
Cout <"\ nfind the string \ n ";
Else cout <"not find the string \ n ";
If (VP. First! = VP. Second)
Cout <"there are" <distance (VP. First, VP. Second) <"AAA \ n ";

#. Enable iterator (I) to point to const iterator (CI)

Typedef vector <int >:: iterator ITER;
Typedef vector <int >:: const_iterator constiter;
There is no implicit type conversion from iterator to const iterator, and iter I (const_cast <ITER> (CI) cannot be used; Because iterator (I) and const iterator (CI) is two completely different types
You can use the following tips:
Advance (I, distance <constiter> (I, CI); // enables I to point to the element that the CI points
Suggestion: Use iterator instead of const_iterator and reverse_iterator.

#. Algorithms that can only operate on ordered data

Search algorithms: binary_search, lower_bound, upper_bound, interval _range,
Set_union, set_intersection, set_difference, set_symmetric_difference
Merge, inplace_merge primary des
It is generally used for ordered intervals: Unique, unique_copy

#. Ensure that the comparison functions used for algorithms are consistent with those used for sorting

Sort (V. Begin (), V. End (), greater <int> ())
// Bool it = binary_search (V. Begin (), V. End (), 5); // error is in ascending order by default, leading to undefined Behaviors
Bool it = binary_search (V. Begin (), V. End (), 5, greater <int> ());

#. Use accumulate and for_each to calculate the interval

# Include <numeric> // include accumulate
Double sum = accumulate (v. begin (), V. End (), 0.0 );

#. Ptr_fun (), mem_fun (), and mem_fun_ref () Usage

Ptr_fun () converts a pointer to a function into a function object. The function must be a mona1 or binary function (it cannot be a function without parameters)
Transform (begin, end, DEST, not1 (ptr_fun (fun )));

Mem_fun and mem_fun_ref are added to the STL algorithm to regard the member functions as parameters, as follows:
List <widget *> lpw;
For_each (lpw. Begin (), lpw. End (), mem_fun (& Widget: Test); // PW-> test ();

Vector <widget> VW;
For_each (VW. Begin (), VW. End (), mem_fun_ref (& Widget: Test); // W. Test ();
The role and usage of mem_fun_ref are the same as those of mem_fun. The only difference is that mem_fun_ref is used when the container stores object entities, mem_fun is used when containers store object pointers.

#. Avoid modifying the set and Multiset keys in situ

Here, the "key part" refers to the part of the object t stored in set/Multiset that has an impact on the set/Multiset sorting algorithm, or the part involved in sorting. For example, in the following example, user: ID:
Class user {
Public:
Unsigned int ID;
String name;
Unsinged int age;
Const string & gettitle () const;
Void settitle (string & title );
};
Class useridless: Public binary_function <user, user, bool> {
Public:
Operator () (const user & LHS, const user & RHs) const {
Return LHS. ID <RHS. ID;
}
};
Typedef set <user, useridless> iduserset;

When modifying objects in set/Multiset, be sure not to change the object key (the part that affects the set/Multiset Sorting Algorithm); otherwise, the container will be damaged.
If you must change the key, take the following policy:
1. Find the object to be modified. I = set. Find ();
2. Copy the object. User B (* I );
3. Modify the Copied object. B. changesome ();
4. Delete the original object. Set. Erase (I ++); // The auto-incrementing iterator to keep it valid.
5. Insert the Copied object. Set. insert (I, B );

#. Correct implementation of copy_if (no copy_if exists in STL)

# Include <iostream>
# Include <vector>
# Include <functional>
# Include <iterator>
# Include <algorithm>
Using namespace STD;

Template <typename inputiterator, typename outputiterator, typename predicate>
Outputiterator copy_if (inputiterator begin, inputiterator end, outputiterator destbegin, predicate P)
{
While (begin! = End)
{
If (P (* begin) * destbegin ++ = * begin;
++ Begin;
}
Return destbegin;
}

Int main ()
{
Int A [] = };
Vector <int> V (A, A + sizeof (a)/sizeof (INT ));
Cout <"\ noutput the number greater than 4: \ n ";
Copy_if (V. Begin (), V. End (), ostream_iterator <int> (cout, ""), bind2nd (greater <int> (), 4 ));
Cout <"\ noutput the number greater than 4: \ n ";
// There is no copy_of in STL, but there is remove_copy_of
Remove_copy_if (V. Begin (), V. End (), ostream_iterator <int> (cout, ""), bind2nd (less_equal <int> (), 4 ));

Return 0;
}

#. Make the imitation function class adaptive

Ptr_fun allows four standard function adapters (not1, not2, bind1st, and bind2nd) to have some typedef. The function objects that provide these necessary typedef are called adaptive.
Operator () carries a real parameter-like function class. The inherited structure is STD: unary_function. Operator () contains two real-name function classes. The inherited structure is STD: binary_function.
Unary_function and binary_function are templates, so you cannot inherit them directly. Instead, you must inherit from the classes they produce, and you need to specify some type arguments. For unary_function, you must specify the type of the parameter included in operator () of your imitation function class and its return type. For binary_function, you must specify three types: the type of the first and second parameters of your operator, and the type returned by your operator.
Two examples:
Template <typename T>
Class meetsthreshold: Public unary_function <widget, bool>
{
PRIVATE:
Const t threshold;

Public:
Meetsthreshold (const T & threshold );
Bool operator () (const widget &) const;
...
};

Struct widgetnamecompare: Public binary_function <widget, widget, bool>
{
Bool operator () (const widget & LHS, const widget & RHs) const;
};
In general, const and reference are removed for non-pointer types passed to unary_function or binary_function.

This rule changes when the operator () parameter is a pointer. Here there is a structure similar to widgetnamecompare, but this uses the widget * pointer:
Struct ptrwidgetnamecompare: Public binary_function <const widget *, const widget *, bool>

{
Bool operator () (const widget * LHS, const widget * RHs) const;
};

#. Others

The class in template <class T1, class T2, class T3 = A> indicates the type, which cannot be replaced by struct, but can be replaced by typename.

When a member of a template type needs to be prefixed with typename, but cannot use class or struct
Typename vector <t >:: iterator it = V. Begin ();

Use empty () instead of checking whether size () is 0
When adding an element to a map, insert is more efficient than operator [].
OPERATOR [] is highly efficient when updating elements already in map.
Use algorithms instead of handwritten Loops
Use a member function instead of an algorithm of the same name.

In C ++, overloading [] requires two versions to meet the requirements:
Char & string: operator [] (int n)
{
Return ch [N];
}
Const char & string: operator [] (int n) const
{
Return ch [N];
}

 

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.