More Effective C ++ Terms 28 (below)

zhaozj2021-02-08  360

Terms 28: Smart (SMART) pointer (below)

Translator Note: Since I can't put pictures in the document area (in the forum asking, the result is no one answer), so only the Word documentation of this translation. download

This technique gives us almost all the behaviors that you want. Suppose we use a new class Cassingle to expand the MusicProduct class hierarchy, used to represent Cassette Singles. The modified class hierarchy looks like this:

Now consider this code:

Template //, including the same type

Class SmartPtr {...}; // Member Template for Conversion Operator

Void Displayandplay (Const Smartptr "MusicProduct> & PMP,

Inthnmany;

Void DisplayandPlay (Const Smartptr "Cassette> & PC,

Inthnmany;

Smartptr Dumbmusic (New Cassingle ("Achy Breaky Heart");

DisplayandPlay (Dumbmusic, 1); // Error!

In this example, DisplayandPlay is overloaded, a function with the SmartPtr parameter, other functions of the parameters of other functions, we expect to call SmartPtr , because Cassingle is inherited directly from Cassette, And it is just indirectly inherited from MusicProduct. Of course this is the working method of the Dumb pointer, our dexterity pointer will not be so flexible. They use the member function as a conversion operator. For the C compiler, all type conversion operators are the same, there is no good or bad. Therefore, DisplayandPlay has an amphony because the type conversion from SmartPtr to SmartPtr is not better than the type of SmartPtr .

There are two disadvantages of the type conversion of the intelligence pointer through the member template. First, support member templates have few compilers, so this technology does not have portability. There will be change in the future, but no one knows when this will wait. Second, this method is not very clear. To understand it must first understand the parameter matching of function calls, implicit type conversion functions, template functions implicit instantiation and member function template. Some of the programmers have never seen this skill, but they are required to maintain the code of this technique, I am very pity. This skill is indeed very clever, which is naturally affirmation, but it is too dangerous thing to be a dangerous thing.

Don't turn around, say it directly, we want to know that how can we make the dexterous pointer to be the same as the DUMB pointer in the inheritance class. The answer is simple: impossible. As Daniel EDELSON said, the smart pointer is in a smart, but not a pointer. The best way is to use the member template to generate type conversion functions, using CASTS in places that generate unisforced results (see Terms 2). This is not a perfect way, but it is also very good. In some cases, except for the second meaning, the cost paid is worthy of compared to the smart pointer.

Lingqi pointer and const

For DUMB pointers, const can either the pointer to what the pointer itself, or both the meaning of both (see Effective C Terms 21): CD GoodCD ("Flood");

Const CD * p; // P is a Non-Const pointer

/ / Point to the Const CD object

CD * const p = & goodcd; // p is a const pointer

/ / Point to the Non-Const CD object;

// Because P is const, it

/ / Must be initialized

const cd * const p = & goodcd; //p is a const pointer

// Point to a const cd object

We naturally want to make the smart pointers have the same flexibility. Unfortunately, it can only place const in one place and can only work on the pointer itself, but cannot be targeted to the object:

Const SmartPtr P = // P is a constimer pointer

& goodcd; // Point to Non-Const CD objects

It seems that there is a simple remedy, which is to build a smart pointer to the COSNT CD:

SmartPtr p = // p is a Non-Const smart pointer

& goodcd; // Point to Const CD objects

Now we can build four different combinations of Const and Non-Const objects and pointers:

SmartPtr P; // Non-Const Object

// Non-const pointer

SmartPtr p; // const object,

// Non-const pointer

Const SmartPtr P = & GoodCd; // Non-Const Object

// Const pointer

Const SmartPtr p = & goodcd; // const object

// Const pointer

However, it is not enough to use the DUMB pointer to initialize the const pointer with the non-const pointer, and we can also initialize the pointer to the Non-COSNT object; just like assignment. E.g:

CD * PCD = New CD ("Famous movie themes");

Const CD * pconstcd = pcd; // correct

But what if we try to put this method in a smart pointer?

Smartptr PCD = New CD ("Famous movie themes");

SmartPtr PConstCD = PCD; / / correct?

SmartPtr is a completely different type with SmartPtr . In the compiler, they are unrelated, so there is no reason to believe they are compatible. So far this is an old problem, the only way to turn them into assignments is that you must provide a function to convert the SMARTPTR type object to SmartPtr CD> type. If you use the compiler to support member templates, you can use the tips you will automatically generate the implicit type conversion operation you need. (I have said before, as long as the corresponding DUMB pointer can make type conversion, the smart pointer can make type conversion, I don't deceive you. There is no problem with the const type conversion.) If you don't have this compiler, you have to overcome More difficult. The type conversion including const is one-way: conversions from Non-Const to Const are secure, but is not secure from const to Non-Const. And use the CONST pointer to do it, but use the Non-Const pointer to do some other things (for example, assignment) with the Non-Const pointer. Similarly, use anything you can do with a pointer to ConST, you can use a pointer to the non-const, but you can do something you can't do with the pointer to the Non-Const (for example, assignment). operating).

These rules look like the rules inherited from public inheritance (Effective C Terms 35). You can convert a derived class object into a base class object, but it is not the case, you can do anything to the base class, but you can do some things to do. We can use this to practice the smart pointer, that is, let each of the smart pointers PUBLIC derived from a corresponding Const-T of the intersection pointer:

Template // Points to Const objects

Class SmartPTRTOCONST {/ 灵巧 pointer

... // Spiritic pointer usually

// member function

protected:

Union {

Const t * constpointee; // Let SmartPTRTOCONST access

T * pointee; // Let SmartPtr access

}

}

Template // Point to Non-Const objects

Class Smartptr: // Lingering Pointer

Public SmartPTRTOCONST {

... // No data member

}

Using this design method, pointing to the Non-Const-T object contains a DUMB pointer to the Const-T, pointing to the integrity pointer to Const-T requires a DUMB pointer to COSNT-T. The most convenient way is to put the DUMB pointer to the const-t in the base class, put the DUMB pointer to the non-const-t in the derived class, but do some waste, because the SmartPtr object contains two DUMB pointers: One is inherited from SmartPTRTOCONST, one is smartptr himself.

A vintage weapon in the Class C can solve this problem, which is Union, which is equally useful in C . Union in protected, so two classes can access it, which contains two must-have DUMB pointer types, SmartPTRTOCONST objects use the constpointee pointer, SmartPtr object uses the Pointee pointer. Therefore, we can use two different pointers without allocating additional spaces (see another example in Effective C Terms 10) This is the beautiful place in Union. Of course, the member functions of the two classes must be confined to use the appropriate pointers. This is the risk of using UNION. Using this new design, we can get the behavioral characteristics of the required behavior:

Smartptr PCD = New CD ("Famous movie themes");

SmartPTRTOCONST PCONSTCD = PCD; / / correct

Evaluation

The discussion of the dexterity pointer is over. Before we leave this topic, you should ask such a question: the smart pointer is so cumbersome, whether it is worthwhile, especially if your compiler lacks support member function template.

It is often worth it. For example, the reference count code in Terms 29 is greatly simplified by using the dexterity pointer. Moreover, as shown in this example, the use of smart pointers is extremely limited in some areas, such as test null values, converted to DUMB pointers, and inherits the support to base classes, and supports pointers to Const. At the same time, the practical, understanding, and maintenance of the dexterity pointer requires a lot of skill. Debug uses the code of the smart pointer than the code of the DUMB pointer using the DEBUG. No matter how you are not possible to design a generic purpose, you can replace DUMB pointers.

The same code effect is achieved, which is more convenient to use the dexterity pointer. The delegation should be used with caution

,

Only

C

The programmer will eventually find them useful.

转载请注明原文地址:https://www.9cbs.com/read-987.html

New Post(0)