Effective C ++ 2e Item17

zhaozj2021-02-11  188

Terms 17: Check the case where you assign yourself in Operator =

When doing things like the following things, you will have your own value:

Class x {...};

X a;

A = a; // a assignments to yourself

This kind of thing is like a very boring, but it is completely legal, so seeing the programmer does not feel the silk.

Suspected. More importantly, you can assign a value to yourself in the form of a more concealed form.

appear:

A = B;

If B is another name of A (for example, it has been initialized to a reference), this is also assigned to yourself,

Although it looks not like the surface. This is an example of an alias: there are more than two names in the same object. in

The final meeting will be seen that alias can appear in a large number of arbitrary forms, so when you write a function

It is necessary to take into account it.

Special attention in the assignment operator may have an alias that may have an alias, which is based on two points. One of them is effective

rate. If you can detect the first part of the assignment operator, you can return it immediately,

This saves a lot of work, otherwise you must implement the entire assignment operation. For example, the terms 16 pointed out, one

The correct derived assignment operator must call the assignment operator of each base class, so in the derived

The operation of omitting the value of the operator in the class will avoid a large number of calls to other functions.

Another more important reason is to ensure the correctness. An assignment operator must first release a subject of an object

Source (removed the old value) and assign new resources based on the new value. In the case of assigning yourself, release

Old resources will be catastrophic because old resources are required when allocating new resources.

See the assignment of the String object below, the assignment operator does not check the case to assign yourself:

Class string {public: string (const char * value); // Function Definition See Terms 11 //

~ String (); // Function Definition See Terms 11 // ...

String & Operator = (const string & rhs);

PRIVATE: CHAR * DATA;

// Ignore the case // of the assignment of the value String & String :: operator = (const string & r Hs) {delete [] data; // delete old memory

// Distribute a new memory, copy the value of RHS to it Data = new char [strlen (rhs.data) 1]; struct (data, rhs.data);

Return * this; // see item 15}

See what will happen in this situation below:

String a = "hello";

A = a; // Same as a.operator = (a)

The assignment operator is inside, * this and rhs seem to be different objects, but in this situation, they happen.

Is the same name of the same object. This will be used to indicate this situation:

* this data ------------> "Hello / 0" / / RHS Data -----

The first thing to assign the operator is to remove Data with delete, and the result will be as follows:

* this data --------------- Now, the result will not be determined when the assignment operator calls Strlen on RHS.DATA. This is because Data is

RHS.DATA is also deleted, DATA, THIS-> DATA and RHS.DATA are actually the same

pointer! From this point, the situation will only become more and more bad.

Now you can know that solving the problem is to check the case that you may have to assign yourself.

If you have this situation, you will return it immediately. Unfortunately, this kind of check is easy to do, because you

It is necessary to define how two objects are "the same".

The problem you face is academically called Object Identity, which is very famous in the object-oriented field.

topic. This book is not a place to describe Object Identity, but it is necessary to mention two solving this problem.

basic method.

One way is that if the two objects have the same value, they are the same (with the same identity)

. For example, if both String objects are represented by the same sequence, they are the same:

String a = "hello"; string b = "world"; string c = "hello";

A and C have the same value, so they are considered exactly the same; B and they are different. If this is

In the STRING class, the assignment operator looks like this:

String & string :: Operator = (const string & rhs) {ix (strcmp (data, rhs.data) == 0) return * this;

...

}

The value is typically detected by Operator ==, so for a class C that detects the identity of the object with a value equal to it.

Say, its general form of the assignment operator is:

C & C :: Operator = (const c & rhs) {// Check the case IF (* this == rhs) // assumes Operator = there is Return * this;

...

}

Note that this function is more than object (via Operator =) instead of a pointer. Determine

There is no relationship between identity and two objects to take the same memory; there is only the value they represent.

Another way to determine if the identity is the same is to use a memory address. Use this definition, two objects

The same only when they have the same address. This definition is widely used in C programs, possibly

It is because it is easy to achieve and the calculation is very fast, and the definition of the same value is not necessarily always with these two excellent

point. Using the definition of the address, a normal assignment operator looks like this:

C & C :: Operator = (Const C & RHS) {// Check the case IF (this == & r HS) return * this;

...

}

It applies to many programs.

If a more complex mechanism is needed to determine if the two objects are the same, this will rely on the programmer himself.

. The most common method is to implement a member function that returns an object identifier:

Class C {public: ObjectId Identity () const; // see Terms 36

...

}

For two objects pointers A and B, when and only when A-> Identity () == b-> Identity (), the objects they refer are identical. Of course, you must implement ObjectIDS's Operator ==.

Alias ​​and Object Identity's issues are not only limited to Operator =. In any function for use

It may be encountered. In the case of reference and pointers, any two compatible types of object names may

Refers to the same object. The other scenarios are listed below:

Class base {void MF1 (Base & RB); // RB and * this may be the same ...

}

Void F1 (Base & RB1, BASE & RB2); // RB1 and RB2 may be the same //////

Class Derived: Public Base {Void MF2 (Base & RB); // RB and * this may be the same // ...

}

INT F2 (Derived & RD, Base & RB); // RD and RB may be the same ////

These examples just use the reference, the pointer is the same.

It can be seen that alias can appear in various forms, so don't forget it or expect you to never touch

it. Maybe you won't touch it, but most of us will encounter. And obvious one is to deal with it.

Half-level effect. So write a function at all times, as long as the alias is likely to appear, you must write code.

Time processing.

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

New Post(0)