More Effective C ++ Terms 20

zhaozj2021-02-08  211

Terms 20: Assist in completing return value optimization

A function of a return object is difficult to have a high efficiency because the transmission value returns to cause constructors and destructors within the object (see Terms 19), which cannot be avoided. The problem is very simple: a function either returns to the object to ensure that the right behavior is either do. If it returns an object, there is no way to get rid of the object being returned. That is.

Consider the member function of the Rational (rational number) class Operator *:

Class russ {

PUBLIC:

Rational (int name = 0, int devenoman = 1);

...

INT numerator () const;

INT Denominator () Const;

}

// Why is the return value is Const's explanation, see Terms 6,

Const Rational Operator * (Const Rational & LHS,

CONST RATIONAL & RHS);

Even if you don't have to look at the code of the Operator *, we know that it must return an object because it returns two calculations of the two arbitrary numbers. These results are any number. Operator * How can I avoid establish a new object to accommodate their calculation results? This is impossible, so it must build a new object and return it. However, C programmers still spend a lot of effort to find the legendary approach, and can remove the object returned (see Effective C Terms 23 and Terms 31).

Sometimes people return pointers, resulting in this funny syntax:

// An unreasonable way to avoid returning objects

Const Rational * Operator * (Const Rational & LHS,

CONST RATIONAL & RHS);

Rational a = 10;

Rational B (1, 2);

Rational C = * (a * b); // Do you think this is "normal"?

It also triggers a problem. Call should delete a function to return a pointer to an object? The answer is usually affirmative and usually leads to resource leakage.

Other developers will return references. This method can generate acceptable syntax,

// A dangerous (and incorrect) method used to avoid returning objects

Const Rational & Operator * (Const Rational & LHS,

CONST RATIONAL & RHS);

Rational a = 10;

Rational B (1, 2);

Rational C = a * b; // look reasonable

But the function cannot be implemented correctly. A try method is like this:

// Another dangerous method (and incorrect) method for

/ / Avoid returning objects

Const Rational & Operator * (Const Rational & LHS,

Const Rational & RHS)

{

Rational Result (lhs.numerator () * rhs.Numerator (),

LHS. Denominator () * rhs.denominator ());

Return Result;

}

The reference to this function returns, the object to which it points to it already exists. It returns a reference to the local object Result, and the result is automatically released when Operator * exits. Returns a reference to the object that has been released, this reference is absolutely unused.

I believe me: some functions (Operator * also) must return to objects. This is their way of operation. Don't confront them, you won't win. The efforts you eliminate the object returned to the value will not get victory. This is a wrong war. From the viewpoint of efficiency, you should not care about the object returned by the function, you just care about the overhead of the object. What you should care is to guide your efforts to find a reduction in the overhead of returning objects, not to eliminate the object itself (we recognize this finding is useless). If there is no overhead associated with these objects, who will care about how many objects have been established?

Returns an object in a way, allowing the compiler to eliminate the overhead of the temporary object, so writing a function is usually very common. This skill is to return to constructor argument instead of returning to objects, you can do this:

// A high efficiency and correct method for implementation

// Return to the object of the object

Const Rational Operator * (Const Rational & LHS,

Const Rational & RHS)

{

Return Rational (LHS.NUMERATOR () * rhs.Numerator (),

LHS. Denominator () * rhs.denominator ());

}

Carefully observe the return of the returned expression. It looks like a constructor that is calling Rational, is actually true. Create a temporary Rational object through this expression,

Rational (lhs.numerator () * rhs.Numerator (),

LHS. Denominator () * rhs.denominator ());

And this is a temporary object, the function copies it to the return value of the function.

Returns a local object without local objects, this method will bring you a lot of overhead, because you still have to pay for the constructive and release of the temporary object within the function, you still have to return to the object and release of the object. And pay the price. But you have gained benefits. The C rules allow the compiler to optimize the Temporary Objects Out of Existence. So if you call Operator * in the following environment *:

Rational a = 10;

Rational B (1, 2);

Rational C = a * b; // Calling Operator * here

The compiler will be allowed to eliminate the temporary variables returned by the temporary variables within Operator *. They can construct an object of Return expression definitions in memory that is allocated for target C. If your compiler is done, the overhead of the temporary object calling Operator * is zero: there is no temporary object. Your price is to call a constructor - the constructor that is called when c is created. And you can't do better than this, because C is a named object, and the name object cannot be eliminated (see Terms 22). However, you can also eliminate the call overhead of Operator * by declaring the function as inline (but first see Effective C Terms 33):

// the Most Efficient Way to Write a Function Returning

// an Object

Inline const rulator * (Const Rational & LHS,

Const Rational & RHS)

{

Return Rational (LHS.NUMERATOR () * rhs.Numerator (),

LHS. Denominator () * rhs.denominator ());

}

"Well, Yes", you said, "Optimize, what can I do with the compiler? I want to know what they do, does any of this nonsense work with real compilers?" It does. This special optimization - eliminates local temporary objects by using the Return Location of the function (or replacing objects in the function call location) - is well known and generally implemented. It does even have a name: Return Value Optimization. In fact, this optimization has its own name itself to explain why it is widely used. Search for programmers for the C compiler to ask if the vendor compiler has a return value optimization function. If a seller says there is another question "What is it?", The first seller will have obvious competitive advantage. Ah, capitalism, sometimes you should love it. (On behalf of the author's point of view, the translator resolutely supports the four basic principles translators Note :-))

appendix:

How to translate the last black body part of the text, I am not allowed, please tell the master, I will attach this article here in this article in this article:

"Yeah, yeah," you mutter, ".? Optimization, schmoptimization Who cares what compilers can do I want to know what they do do Does any of this nonsense work with real compilers.?" It does This particular optimization -. Eliminating a local temporary by using a function's return location (and possibly replacing that with an object at the function's call site) - is both well-known and commonly implemented It even has a name:.. the return value optimization In fact, the existence of a name for this optimization may explain why it's so widely available. Programmers looking for a C compiler can ask vendors whether the return value optimization is implemented. If one vendor says yes and another says "The what ?," the first vendor has a notable competitive Advantage. Ah, Capitalism. Sometimes You Just Gotta Love IT.

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

New Post(0)