Effective C ++ 2e Item12

zhaozj2021-02-11  193

Terms 12: Try to use initialization instead of assigning the constructor

Look at such a template, the class it generates makes a name and a pointer to the T type object.

Template class namedptr {public: namedptr (const string & initname, t * initptr); ...

PRIVATE: STRING NAME; T * PTR;

(Because the object of the pointer member may cause a pointer chaos when copying and assigning operations (see Terms 11), NamedPTR must also implement these functions (see clause 2))

When writing the NAMEDPTR constructor, the parameter value must be passed to the corresponding data member. There are two ways to achieve. The first method is to use a member initialization list:

Template Namedptr :: Namedptr (const string & initname, t * initptr): name (initname), PTR (INITPTR) {}

The second method is to assign a value in the constructor:

Template Namedptr :: Namedptr (const string & initname, t * initptr) {name = initname; ptr = initptr;}

Two methods have a significant difference.

From the perspective of pure practical applications, in some cases, initialization must be used. In particular, const and reference data members can only be assigned with initialization. So, if you want the NamedPtr object to change its name or pointer member, you must follow the recommended statement of the clause 21 as const:

Template class namedptr {public: namedptr (const string & initname, t * initptr); ...

PRIVATE: Const string name; t * const ptr;};

The definition of this class requires the use of a member to initialize a list, because Const members can only be initialized and cannot be assigned.

If the NamedPtr object contains a reference to an existing name, it will be very different. But still to initialize the reference in the initialization list of constructor. You can also declare const and reference at the same time, which generates a member of its name that can be modified outside the class and is within the interior.

Template class namedptr {public: namedptr (const string & initname, t * initptr); ...

Private: const string & name; // must initialize the list // through member initialization list

T * const ptr; / / must be initialized by the member initialization list //;

However, the initial class template does not include const and reference members. Even in this way, the list of initialization is still better than the value in the constructor. This reason is efficient. When using a member to initialize a list, only one String member function is called. When it is assigned to the constructor, there will be two calls. To understand why, what happened when declaring the Namedptr object.

The creation of the object is two steps: 1. Data member initializes. (See Terms 13) 2. Execute the action in which the invoked constructor is called.

(For the object of the base class, the member initialization of the base class is initialized and the execution of the constructor is initialized and the implementation of the members of the derived class.

For the NamedPTR class, this means that the constructor of the String object Name is always called before the program executes the configuration function of the Namedptr. The problem is only: Which constructor is called in String?

This depends on the list of members initialized by the NamedPtr class. If the initialization parameter is not specified for the NAME, the default constructor of String is called. When the name is assigned to the NAME in the constructor of the NamedPtr, the Operator = function is called. This has a total of two calls to String members: One is the default constructor, and the other is assignment.

Conversely, if you initialize a list with a member to specify that Name must be initialized with initName, Name will be initialized by the copy constructor by the copy constructor.

Even a very simple String type, unnecessary function calls can also cause high cost. As the class is getting bigger, it is increasingly complex, and their constructor is getting bigger and complicated, then the cost of object creation is also higher and higher. Developing habits that use Member initialization lists, not only meetings of consT and reference members, but also greatly reduce opportunities to initialize data.

In other words, the initialization of the member initialization is always legal, and the efficiency is not less than the assignment in the constructor, it will only be more efficient. In addition, it simplifies the maintenance of class (see Terms M32), because if a data member is modified into a certain data type that must be initialized by the member, then nothing is used.

In one case, the assignment of the class's data member is more reasonable with initialization. This is when there is a large number of fixed types of data to initialize in the same way in each constructor. For example, there is a class that can be used to illustrate this situation:

Class ManydataMBrs {public: // Default constructor MANYDATAMBRS ();

// Copy constructor Manydatambrs (const portrativeDataMBRS & X);

Private: Int A, B, C, D, E, F, G, H; Double I, J, K, L, M;}

If you want to initialize all Int to 1, all Double initializes 0, then use the member initialization list to write:

Manydatambrs :: Manydatambrs (): A (1), B (1), C (1), D (1), E (1), F (1), G (1), H (1), I (0 ), J (0), K (0), L (0), M (0) {...}

Manydatambrs :: Manydatambrs (Const Manydatambrs & X): a (1), B (1), C (1), D (1), E (1), F (1), G (1), H (1), I (0), J (0), K (0), L (0), M (0) {...}

This is not just an annoying and boring work, and it is easy to make mistakes from the short term. It is difficult to maintain from a long time.

However, you can use the fixed data type (non-Const, non-reference) object whose initialization and assignment does not operate different features, safely use a member initialization column to use a call to the normal initialization function.

Class ManydataMBrs {public: // Default constructor MANYDATAMBRS ();

// Copy constructor Manydatambrs (const portrativeDataMBRS & X);

Private: INT A, B, C, D, E, F, G, H; Double I, J, K, L, M Download Adobe Reader

Void init (); // Used to initialize data member};

Void mandatambrs :: init () {a = b = c = D = E = f = g = H = 1; i = j = k = l = m = 0;}

Manydatambrs :: bodydatambrs () {init ();

...

}

Manydatambrs :: Manydatambrs (const portrativedatambrs) {init ();

...

}

Because the initialization function is just an implementation details of the class, of course, it is necessary to declare it as a Private member.

Note that Static class members will never initialize the constructor of the class. Static members are only initialized once in the process of running, so it doesn't make anything when it is created when the class object is created. At least this will affect efficiency: since it is "initialization", why do you want to do multiple times? Moreover, the initialization of static members is very different from non-static members, which has a special Terms M47 to illustrate.

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

New Post(0)