New functions in the Standard C ++ Library
As I mentioned, the Feature Pack also includes adding to Standard C ++ as part of tr1
A large number of additional functions in the library. This includes smart pointers that support reference counting, multi-state function packaging, containers based on hash tables, and regular expressions. Below I will introduce some of the new tr1 functions. Polymorphism function object
In many applicationsProgramThere is a vital function in both, that is, the function can be referenced as a value and can be passed or stored as a parameter for future use. This concept can be used to implement various common structures, including callback functions, event handlers, and asynchronous programming functions. However, the function
C ++ is very difficult to process. The driving force of function design mainly comes from
And the requirements for excellent performance. Although these goals are achieved, it is not easier to regard functions as objects that can be stored, passed, and finally asynchronously called. Let's take a look.
The construction of common functions in C ++.
First, it is a good old non-member function:
Copy code
Int add (int x, int y) {return X + Y ;}
Normally, you can call it as follows:
Copy code
Int result = add (4, 5); Assert (4 + 5 = Result );
Another common function-like construction is a function object (that is, an operator ):
Copy code
Class addfunctor {public: int operator () (int x, int y) const {return x + y ;}};
Because it implements call operators, function objects can be used like functions:
Copy code
Addfunctor fo; int result = fo (4, 5); Assert (4 + 5 = Result );
The following are non-static member functions:
Copy code
Class adder {public: int add (int x, int y) const {return x + y ;}};
Of course, you need to use an object to call a member function:
Copy code
Adder adder; int result = adder. Add (4, 5); Assert (4 + 5 = Result );
So far, everything went well. Now, assume that you need to store the construction of these similar functions for future use. You can define a type that can store pointers to non-member functions as follows:
Copy code
Typedef int (* functionpointertype) (int x, int y );
You can also use the function pointer as a function:
Copy code
Functionpointertype fp = & add; int result = FP (4, 5); Assert (4 + 5 = Result );
Although function objects can also be stored, they cannot be stored in the form of polymorphism together with function pointers.
Member functions can be stored in pointer-to-member-function:
Copy code
Adder adder; typedef int (adder: * memberfunctionpointertype) (int x, int y); memberfunctionpointertype MFP = & adder: Add;
However, the pointer-to-member-function type and
Pointer-to-non-member-Function
The type is not compatible, so it cannot be stored in the form of polymorphism together with non-member function competitors. Even if possible, a member function still needs an object to provide the context for calling the member function:
Copy code
Int result = (adder. * MFP) (4, 5); Assert (4 + 5 = Result );
I think you should understand what I mean without further explanation. Fortunately, the new tr1: Function
Class templates provide a solution. Tr1: Function
A class template saves a callable object for the function type defined in its template parameters. Next, I will use a non-member function to initialize it:
Copy code
Function <int (int x, int y)> F = & add; int result = f (4, 5); Assert (4 + 5 = Result );
Using function objects for initialization is equally easy:
Copy code
Function <int (int x, int y)> F = addfunctor ();
You can even use the new function binding function to initialize it through the member function:
Copy code
Function <int (int x, int y)> F = BIND (& adder: add, & adder, _ 1, _ 2 );
Bind
I will introduce the function content later, but here you need to know that you can now bind a single function package to non-member functions, function objects, and even member functions. It can be stored and called at any time in the future, all of which are implemented in the form of polymorphism.
Function packaging can also be rebound, and can be set to a null value like a common function pointer:
Copy code
Function <int (int x, int y)> F; Assert (0 = f); F = & add; Assert (0! = F); F = BIND (& adder: add, & adder, _ 1, _ 2 );
The functions of the BIND function template are much more powerful than the function object adapters in the Standard C ++ library-especially
STD: bind1st () and STD: bind2nd (). In this example, bind
The first parameter is the address of the member function. The second parameter is the object address, in which case the Member will be called. The last two parameters in this example define the placeholders to be parsed when a function is called.
Of course, BIND is not limited to member functions. You can bind the multiplies of the Standard C ++ Library
Function object to create a square function. Using this function, you can generate a single parameter function that can produce the square result of the parameter:
Copy code
Function <int (INT)> Square = BIND (multiplies <int> (), _ 1, _ 1); int result = square (3 ); assert (9 = Result );
Note that the tr1: function class template is very suitable for use with standard C ++
LibraryAlgorithm. Given an integer container, you can use the member function to generate the sum of all values, as shown below:
Copy code
Function <int (int x, int y)> F = // initializeint result = accumulate (numbers. begin (), numbers. end (), 0, // Initial Value F );
Remember, tr1: Function
The class template may prohibit Compiler Optimization (such as inline), but this issue may not occur if you only use function pointers or function objects directly. Therefore, use tr1: function only when necessary.
Class template, for example, when you use a cumulative algorithm that may be repeatedly called. If possible, function pointers, member function pointers (rewritten using mem_fn of tr1), and function objects (such as bind
To the Standard C ++ library algorithm and other templated algorithms.
Let's continue. There will be more interesting questions. Suppose there is a surface class that represents some drawing surfaces, and there is
Shape class, which can draw itself to the surface:
Copy code
Class surface {//...}; Class shape {public: void draw (Surface & surface) const ;};
Now let's take a look at how we can draw every shape in the container to a given surface. You may consider using for_each
The algorithm is as follows:
Copy code
Surface surface = // initializefor_each (shapes. Begin (), shapes. End (), BIND (& shape: Draw, _ 1, surface); // wrong
Here, I plan to use the BIND function template to call the member function for each element of the shape container and bind the surface as a parameter
Draw member function. But unfortunately, it depends on the surface.
May not run or compile as expected. This problem occurs because the BIND function template tries to generate a surface copy when you actually need a reference. Fortunately, tr1
A reference_wrapper class template is also introduced, which allows you to regard reference as a value that can be copied at will. Due to the existence of the type inference function, the ref and CREF function templates can be simplified.
Reference_wrapper object creation process.
With reference_wrapper, for_each
The algorithm can now easily and effectively draw shapes on the surface:
Copy code
For_each (shapes. Begin (), shapes. End (), BIND (& shape: Draw, _ 1, ref (surface )));
As you have imagined, new function packaging, binding functions, and reference packaging can be combined in multiple ways to flexibly solve various problems. Smart pointer
Smart pointers are indispensable tools for C ++ developers. I usually use ccomptr of ATL for processing.
COM interface pointer. The auto_ptr of the Standard C ++ library is used to process the original C ++ pointer. The latter is very suitable for dynamically creating C ++ objects and ensuring that when auto_ptr
When an object is out of range, it can be safely deleted.
Smart pointer like auto_ptr
But it can only be safely used in a few cases. This is mainly because of the ownership transfer semantics it implements. That is, if you copy or assign an auto_ptr object, the ownership of the basic resource will be transferred, the original
Auto_ptr
Object will lose it. It can only play a significant role when you have fine-grained control over resource allocation, but in many cases you may need to share objects. In this case, intelligent pointers that implement shared ownership semantics will be very useful. More importantly, auto_ptr
It cannot be used with the standard C ++ library container.
Tr1 introduces two new smart pointers that work together for multiple purposes. How shared_ptr class templates work
Auto_ptr is very similar, but it cannot transfer the ownership of the resource. It only increases the reference count of the resource. If the last shared_ptr used to save the object reference information
If the object is damaged or reset, the resource is automatically deleted. Use the weak_ptr class template and shared_ptr
The caller can reference resources without affecting the reference count. This is useful if there is a circular relationship in the object model or you plan to implement the cache service. It is also very suitable for use with standard C ++
Library container used together!
For comparison, see the following auto_ptr usage:
Copy code
Auto_ptr <int> aP (New int (123); Assert (0! = Ap. Get (); // transfer ownership from AP to ap2auto_ptr <int> AP2 (AP); Assert (0! = Ap2.get (); Assert (0 = ap. Get ());
The auto_ptr copy constructor transfers ownership from the AP to ap2. Shared_ptr
The behavior is also predictable:
Copy code
Shared_ptr <int> Sp (New int (123); Assert (0! = Sp); // increase reference count of shared objectshared_ptr <int> SP2 (SP); Assert (0! = SP2); Assert (0! = Sp );
Internally, all shared_ptr instances that reference the same resource
All objects share a control block. This control block tracks the number of shared_ptr objects that share resources and the number of weak_ptr objects that reference this resource. I will show you how to use
Weak_ptr template.
A member function similar to auto_ptr is composed of shared_ptr
. These include the unreferencing operator and arrow operator, the reset member function used to replace the resource, and the get that returns the resource address.
Member functions. In addition, it provides some special member functions (including a function exactly named after unique ). Unique member function will test shared_ptr
Whether the object is the only smart pointer that stores resource reference information. Example:
Copy code
Shared_ptr <int> Sp (New int (123); Assert (sp. Unique (); shared_ptr <int> SP2 (SP); Assert (! Sp. Unique (); Assert (! Sp2.unique ());
You can also use the use_count member function to obtain shared_ptr with resources.
Number of objects:
Copy code
Shared_ptr <int> sp; Assert (0 = sp. use_count (); SP. reset (New int (123); Assert (1 = sp. use_count (); shared_ptr <int> SP2 (SP); Assert (2 = sp. use_count (); Assert (2 = sp2.use _ count ());
However, use_count
The purpose is only for debugging, because it cannot be guaranteed to be a constant time operation in all implementations. Please note that the unspecified-bool-type operator can be used to determine
Whether shared_ptr owns resources, and you can use the unique function to determine whether shared_ptr is the only owner of a resource.
Weak_ptr templates store weak references to resources owned by shared_ptr objects. If you have all
The shared_ptr object is damaged or reset, and the resource is deleted, whether or not the weak_ptr object is referencing it. To ensure that weak_ptr is not used
The weak_ptr class template does not provide a get
Returns the resource address or member access operator. On the contrary, you must first convert a weak reference to a strong reference to access the resource. The lock member function provides this function, as shown in figureFigure
8.
Convert figure 8 to strong reference
Copy code
Surface surface; shared_ptr <shape> Sp (new shape); Assert (1 = sp. use_count (); weak_ptr <shape> WP (SP); Assert (1 = sp. use_count (); // still 1 // arbitrary application logic... if (shared_ptr <shape> SP2 = WP. lock () {SP2-> draw (surface );}
If the resource is released midway through, the lock member function of the weak_ptr object will return a function that does not own the resource.
Shared_ptr object. As you can imagine, shared_ptr and weak_ptr will greatly simplify resource management in many applications.
Without a doubt, the visual C ++ 2008 feature package is a popular Visual C ++
Library upgrade programs will definitely come in handy sooner or later! I hope that the introduction in this article will arouse your interest, so that you can take some time to study it in depth.