Effective C ++ 2e Item31

zhaozj2021-02-11  204

Terms 31: Do not return to the reference to local objects, do not return a reference to pointers initialized in the function within the function

This article sounds complicated, in fact. It is just a very simple truth, really, believe me.

First see the first case: return a reference to a local object. Its problem is that local objects ---- as the name suggests ---- is just partial. That is, the local object is created when it is defined, and is destroyed when leaving the living space. The so-called life space refers to the function of their function. When the function returns, the control of the program leaves this space, so all local objects inside the function are automatically destroyed. Therefore, if the partial object is returned, the local object is actually destroyed before the function caller used it.

This problem occurs when the result of the function is to increase the efficiency of the program and return the result of the function. The same examples in the following examples 23, the purpose is to explain how to return references, when should not be:

Class Rational {// An Agree Class PUBLIC: Rational (int name = 0, int devenator = 1); ~ Rational ();

...

PRIVATE: INT N, D; // Molecule and Division

// Note that operator * (incorrectly) returns a reference Friend Const Rational & Operator * (Const Rational & LHS, Const Rational & RHS);

// Operator * Inline Const Rational & Operator * (Const Rational & LHS, Const Rational & Rhs) {Rational Result (lhs.n * rhs.n, lhs.d * rhs.d); Return Result;}

Here, the local object Result is created when the Operator * function is just entered. However, all local objects are automatically destroyed when they leave their space. Specifically, this example, Result is the space where it is left after executing the return statement. So, if you write:

Rational TWO = 2;

Rational Four = Two * Two; // With Operator * (Two, Two)

The following events occur when the function is called:

1. Local object Result is created. 2. Initialize a reference to make it another name; this reference is placed on the other side, leaving the return value of Operator *. 3. Local object Result is destroyed, which can be used by the space occupied by the stack. 4. Initialize the object Four by the reference in step 2.

Everything is normal, until the fourth step has created an error, borrowing the high-tech circle, producing a "a huge mistake." Because, the second step is initialized, the reference to the end of the third step is no longer a valid object, so the initialization result of the object FOUR is completely unsure.

The lesson is obvious: do not return a reference to a local object.

"Well," You may say, "The problem is not that the object wants to use too early? I can solve it. Do not use local objects, you can use new to solve this problem." This is like this:

Operator * Another incorrect implementation of Inline Const Rational & Operator * (Const Rational & LHS, Const Rational & Rhs) {// Create A New Object On The Heap Rational * Result = New Rational (lhs.n * rhs.n, LHS.D * rHS.D); // return it Return * Result;}

This method does avoid problems in the above example, but it has triggered a new problem. Everyone knows that in order to avoid memory leaks in the program, you must ensure that DELETE is called for each pointer generated by New. However, the problem here is that the new use of the New, who is the corresponding delete call?

Obviously, the caller of Operator * should be responsible for calling Delete. Really obvious? Unfortunately, even if you write it, you can't solve the problem. The reason why such a pessimistic judgment is based on two reasons:

First, everyone knows that this kind of programmer is very horses. This doesn't mean you slopes or me, but it means that no programmer can't deal with some of the habit. Want to remember such a programmer to get the result of the pointer and then call DELETE after calling Operator *, how much is this chance? Also, they must use Operator *:

Const Rational & four = two * two; // Get discarded pointers; // exist in a reference ...

Delete & four; // Get the pointer and delete

Such a chance will not be small. Remember, as long as an Operator * caller will cause memory leakage.

Returning the abandoned pointer has another more serious problem, even the most person-oriented programmer is also difficult to avoid. Because this is often in this case, the result of Operator * is only temporarily used for intermediate values, and there is only a larger expression. E.g:

Rational One (1), Two (2), Three (3), FOUR (4); Rational Product;

Product = one * two * three * four;

The calculation expression of Product requires three separate Operator * calls to override this expression in the form of a corresponding function.

Product = Operator * (Operator * (Operator * (ONE, TWO), Three, FOUR)

Yes, each Operator * calls the object returned to be deleted, but unable to call Delete here because there is no return object being saved.

Solving this problem is to call the user to write code:

Const Rational & Temp1 = One * Two; Const Rational & Temp2 = Temp1 * Three; Const Rational & Temp3 = Temp2 * Four;

DELETE & TEMP1; Delete & Temp3;

If so, the best result you can expect is that people will not pay attention to you. More realistic, you will be accused of the sound of the Sound Day, or may be sentenced to the microcode of the Welcome Biscuit or Toaster 10 Years. So I have to remember your lesson: Write a function that returns the abandoned pointer is no different from the arrival of memory leaks.

In addition, if you think that you think of what method you want to avoid the uncertain behavior of "return local object", the memory leaks brought about by "reference to the object allocated on heap", then Please go to Terms 23 to see why the reference to returning a local static (Static) object will work abnormal. After reading it, you may help you avoid the trouble of your headache.

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

New Post(0)