Valid tive C ++, 3rd edition, item 21: When you must return an object, do not try to return a reference (reference) (lower)

Source: Internet
Author: User

(Click here, next to the previous article)

However, you may notice whether it is on-the-stack or on-the-heap (on the stack, every result returned from operator * has to tolerate a constructor call. You may remember that our initial goal was to avoid such constructor calls. Maybe you think you know that a method can avoid nearly all Constructor (constructor) calls. Maybe the following implementation is what you have done. One is based on the returned result, which leads to the definition inside the function.StaticImplementation of operator * of rational object references (reference:

Const rational & operator * (const rational & LHS, // warning! Yet more
Const rational & RHs) // bad code!
{
Static rational result; // static object to which
// Reference will be returned

Result =...; // multiply LHS by RHS and put
// Product inside result
Return result;
}

Just like all the designs that use static objects, This will immediately cause thread-Safety (thread security) chaos, but it is an obvious weakness. To see its deeper defects, consider this completely reasonable customer code:

Bool operator = (const rational & LHS, // an operator =
Const rational & RHs); // For rationals

Rational a, B, c, d;

...
If (A * B) = (C * D )){
Do whatever's appropriate when the products are equal;
} Else {
Do whatever's appropriate when they're not;
}

Guess what will happen? No matter what the values of A, B, C, and D are, the expression (A * B) = (C * D) is always true!

This discovery is easy to understand when code rewriting is another form of equivalent functionality:

If (operator = (Operator * (A, B),Operator * (c, d)))

Note: When operator = is called, there will be two calls to operator * at the same time, each of which will return a reference to the static rational object inside operator. Therefore, operator = is required to compare the value of the static rational object inside operator * with the value of the static rational object inside operator. If they are not always equal, then they will be astonishing.

These should be enough to convince you that it is a waste of time to try to return a reference from a function like operator *, but some of you will now think, "okay, even if a static object is not enough, it may be a static object.Array(Array) is a trick ......"

I cannot come up with sample code to affirm this design, but I can explain why this idea should make you feel ashamed. First, you must selectNAs the size of the array. IfNIf it is too small, you may use up the space to store function return values. Compared with the well-known single-Static Design, you will not get more in any aspect. However, ifNIf it is too large, it will reduce the performance of your program, because when the function is called for the first timeEveryAn object (each object) is constructed. Even if the function we are discussing is called only once, it will make you payNConstructors andNDestructors (destructor) cost. If "optimization" ("optimization") is a process to improve software performance, such things can only be called "pessimization" ("Pessimism. Finally, consider how you put the values you need into the objects array and what you need to do. The most direct way to move a value between two objects is through assignment (assign value), but what will be paid for one assignment (assign value? For many types, this is equivalent to calling a destructor (destructor) (destroy the original value) and calling a constructor (constructor) (copy the new value ). But your goal is to avoid construction and destruction costs! The result is that this method will never succeed. (No, replacing an array with a vector won't improve things much .)

The correct way to write a function that must return a new object is to let the function return a new object ). For rational operator *, this means that the following code or something essentially equivalent to it:

Inline const rational operator * (const rational & LHS, const rational & RHs)
{
Return rational (LHS. N * RHS. N, LHS. D * RHS. D );
}

Of course, you may have paid the cost of constructing and analyzing the return values of operator *, but in the long run, this is only a small price for correct behavior. In addition, the bill that makes you feel terrible may never arrive. Just like all programming languages, C ++ allows the compiler's implementers to Use Optimization without changing the observed behavior of the generated code to improve its performance, under some conditions, the following results are generated: Construction (construction) and destruction (destructor) of operator * can be safely eliminated. When the compiler takes advantage of this (the compiler often does this), your program behavior is still in line with your expectations, but faster than you expect.

All focus is here: if you need to make a decision between returning a reference and returning an object, your job is to select the one that can provide the correct behavior. Let your compiler vendors stick their brains to make that choice as cheap as possible.

Things to remember

  • Never return a pointer or reference to a local stack object. Never return a reference to a heap-allocated object, or, if there is a possibility that more than one such object is required, do not return a pointer or reference to a local static object (local static object. (An example provided by item 4 that returns a reference to the local static (local static) design is at least reasonable in single-threaded environments (single-threaded Environment .)
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.