Valid STL Clause 38

Source: Internet
Author: User
Clause 38: design the imitation function class for value transfer

Neither C ++ nor C ++ allows you to pass functions as parameters to other functions. Instead, you must passPointerTo the function. For example, here is a declaration of the standard library function qsort:

void qsort(void *base, size_t nmemb, size_t size,    int (*cmpfcn)(const void*, const void*));

Cla46 explains why the sort algorithm is generally a better choice than the qsort function, but it is not a problem here. The problem is that the parameter cmpfcn declared by qsort. Once you ignore all asterisks, you can clearly see that as a parameter passed by cmpfcn, a pointer to the function is copied (that is, the value is passed) to qsort from the call end. This is the general principle that both C and C ++ standard libraries follow, that is, function pointers are passed by values.

STL function objects are formed after function pointers, so the habit in STL is that when it is passed to the function and when it is returned from the function, the function object is also a value (that is, a copy ). The best evidence isStandardFor_each declaration of, this algorithm obtains and returns the function object through value transfer:

Template <class inputiterator, class function> function // The value for_each (inputiterator first, inputiterator last, function f) is returned. // The value of attention is transmitted.

In fact, the value transfer is not completely broken, because the for_each caller can explicitly specify the parameter type at the call point. For example, the following code enables for_each to pass and return its imitation functions through reference:

Class dosomething: Public unary_function <int, void> {// Clause 40 explains this base class void operator () (int x ){...}...}; typedef deque <int >:: iterator dequeintiter; // convenient typedefdeque <int> Di ;... dosomething D; // create a function object... for_each <dequeintiter, // call for_each, parameter dosomething &> (Di. begin (), // type is dequeintiter di. end (), // and dosomething &; d); // This forces d to pass and return by reference //

But STL users cannot do this. If function objects are passed by reference, some STL algorithms cannot even be compiled. In the remainder of these terms, I will continue to assume that function objects are always passed through values. In fact, this is always true.

Because function objects are passed and returned by values, your task is to ensure that your function objects behave well when it is passed (that is, copied. This implies two things. First, your function object should be small. Otherwise, their copying will be expensive. Second, your function objects must be single-State (that is, non-polymorphism)-they cannot use virtual functions. This is because the passing of a derived class object as a value to a parameter of the base class type causes the cutting problem: during copying, their derived parts are deleted. (For another example of how the cutting problem affects your use of STL, see clause 3 .)

Of course, efficiency is very important to avoid cutting, but not all of the imitation functions are small and single-State. One of the reasons that function objects are superior to real functions is that the imitation function can contain all the states you need. Some Function objects are naturally very heavy. It is very important to keep passing such imitation functions to the STL algorithm as easily as passing their function versions.

It is impractical to disable the polymorphism function. C ++ supports inheritance layers and dynamic binding. These features are equally useful when designing a function-like class and other things. If the class of the imitation function lacks inheritance, it is like C ++ lacks "++ ". There is indeed a way for large and/or multi-state function objects to still allow them to spread the way in which value-based functions are passed throughout STL.

That's it. Move the data and/or polymorphism that you want to put into your imitation function class to another class. Then, give your function a pointer to the new class. For example, if you want to create a multi-state imitation function class that contains a lot of data.

Template <typename T> class bpfc: // bpfc = "Big polymorphic public // functor class" unary_function <t, void> {// Clause 40 explains this base class private: widget W; // this class has a lot of data, int X; // so use the value to pass... // efficiency will be affected public: Virtual void operator () (const T & Val) const; // This is a virtual function ,... // problems may occur during cutting };

Create a small, single-State class that contains a pointer to the implementation class, and put all the data and virtual functions into the implementation class:

Template <typename T> // The New Implementation class private: widget W of the bpfcclass bpfcimpl {// used for modification; // int X of all data previously stored in bpfc; // here we are now... virtual ~ Bpfcimpl (); // required for Polymorphism classes // virtual destructor virtual void operator () (const T & Val) const; friend class bpfc <t>; // enable bpfc to access the data}; Template <typename T> class bpfc: // small, single-State version of bpfc public unary_function <t, void> {PRIVATE: bpfcimpl <t> * pimpl; // This is the unique public data of bpfc: void operator () (const T & Val) const // It is not virtual now; {// call bpfcimpl pimpl-> operator () (VAL );}...};

The implementation of bpfc: Operator () illustrates how all the virtual functions of bpfc are implemented: they call their real virtual functions in bpfcimpl. The result is that the imitation function class (bpfc) is small and single-state, but it can access a large number of States and its behavior is polymorphism.

I ignored a lot of details here, because the basic technology I outlined has been widely known in the C ++ circle. Among the 34 Terms of Objective C ++. In design patterns such as gamma [6], this is called the Bridge pattern ". In his exceptional C ++ [8], Sutter calls it "pimpl usage ".

From the STL perspective, the most important thing to remember is that the imitation function classes using this technology must support reasonable copying. If you are the author of bpfc above, you must ensure that its copy constructor has done reasonable things for the bpfcimpl object. Perhaps the simplest and most reasonable thing is to reference the counter, using shared_ptr similar to boost, you can understand it in Clause 50.

In fact, for the purpose of these terms, the only thing you have to worry about is the behavior of the bpfc copy constructor, because when it is passed in STL or returned from a function, function objects are always copied-value passing, remember? That means two things. Make them small and make them standalone.

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.