[Translation] effective C ++, 3rd edition, item 20: replace pass-by-reference-to-const (passed to const reference) with pass-by-value (

Source: Internet
Author: User

Item 20: replace pass-by-value with pass-by-reference-to-const (Transfer const reference)

By Scott Meyers

Translator: fatalerror99 (itepub's nirvana)

Release: http://blog.csdn.net/fatalerror99/

By default, C ++ uses the by Value Method to pass in or out objects (a feature inherited from C ). Unless you specify other methods, function parametersCopiesOf the actual arguments (copy of the current real parameter) for initialization, and the function caller will retrieveCopy(Copy ). These copies are generated by the copy constructors (copy constructors) of objects. This makes pass-by-value a costly operation. For example, consider the following class hierarchy ):

Class person {
Public:
Person (); // parameters omitted for simplicity
Virtual ~ Person (); // see item 7 for why this is virtual
...

PRIVATE:
STD: string name;
STD: String address;
};

Class student: public person {
Public:
Student (); // parameters again omitted
Virtual ~ Student ();
...

PRIVATE:
STD: String schoolname;
STD: String schooladdress;
};

(The original article does not explicitly declare student destructor as virtual and modify it according to the author's website Errata-Translator's note .)

Now, consider the following code. Here we call a function validatestudent, which gets a student argument (real parameter) (by value) and returns whether it is valid:

Bool validatestudent (StudentS); // function taking a student
// By Value

Student Plato; // Plato studied under Socrates

Bool platoisok = validatestudent (Plato); // call the Function

What will happen when this function is called?

Obviously, student copy constructor (copy constructor) is called and Plato is used to initialize parameter (shape parameter) s. Similarly, when validatestudent returns, s will be destroyed. Therefore, the parameter-passing cost (parameter transfer cost) of this function is a call of student copy constructor (copy constructor) and a call of student destructor (destructor.

But this is not all. A student object contains two strings objects, so each time you construct a student object, you must also construct two strings objects. A student object must be inherited from a person object. Therefore, each time you construct a student object, you must also construct a person object. One person object contains two other strings, so the structure of each person also bears the construction of the other two strings. In the end, the result of passing a student object in the by value mode is a call to student copy constructor (copy constructor), and a person copy constructor (copy constructor) and four string copy constructor (copy constructor) calls. When a copy of the student object is destroyed, each constructor call (constructor call) corresponds to a destructor call (destructor call), so by value) the total cost of passing a student is six constructors and six Destructors )!

Well, this is correct and worthwhile. After all, you want all your objects to be reliably initialized and destroyed. Even so, if there is a way to bypass all these constructor and destructor processes, it would be better: pass by reference-to-const (pass the const reference ):

Bool validatestudent (ConstStudent&S );

This is very effective: No Constructors (constructors) or Destructors (destructor) are called because no new objects is created. The const in the modified parameter Declaration (parameter Declaration) is very important. In the original version of validatestudent, a student parameter (shape parameter) is obtained by value. Therefore, the caller knows that they shield the function from any possible changes to the student they pass in; validatestudent can only change one of itsCopy(Copy ). Now student is passed by reference. It is also necessary to declare it as Const. Otherwise, the caller must worry that validatestudent has changed the student they passed in.

Passing parameter by reference can also avoidSlicing Problem(Disconnection problem ). When a derived class Object (derived class Object) is passed as a base class Object (base class Object) (by passing values), base class copy constructor (base class copy constructor) called, and the special features that make the object behave like a derived class Object (derived class Object) are "sliced" ("cut. Only one simple base class Object (pure base class Object) is left for you. This is not surprising because it is created by a base class Constructor (base class constructor. This is almost never what you want. For example, suppose you work on a set of classes that implement a graphic Window System:

Class window {
Public:
...
STD: string name () const; // return name of window
Virtual void display () const; // draw window and Contents
};

Class required wwithscrollbars: public window {
Public:
...
Virtual void display () const;
};

All window objects have a name. You can get it through the name function, and all windows can be displayed. You can call the display function to do this. The fact that display is virtual tells you that a simple base class (pure base class) the Display Method of window objects in may be different from the display method of specialized javaswwithscrollbars objects (see items 34 and 36 ).

Now, suppose you want to write a function to print the name of a window and then display the window. The following function is incorrectly written:

Void printnameanddisplay (WindowW) // incorrect! Parameter
{// May be sliced!
STD: cout <W. Name ();
W. Display ();
}

Consider what will happen when you call this function using a javaswwithscrollbars object:

Descriwwithscrollbars wwsb;

Printnameanddisplay (wwsb );

Parameter (parameter) W will be used asWindowObject Construction -- it is passed by value, remember? In addition, the special information of the wwsb object is cut off. In printnameanddisplay, regardless of the type of the object passed to the function, W will always behave like a class window object (because it is a class window object ). In particular, the call to display in printnameanddisplay willAlways(Always) Call window: display. It will never be javaswwithscrollbars: display.

The method to bypass slicing problem (disconnection problem) is to pass W by reference-to-const (Transfer const reference:

Void printnameanddisplay (ConstWindow&W) // fine, parameter won't
{// Be sliced
STD: cout <W. Name ();
W. Display ();
}

Now w will look like the window actually passed in.

(This Article is not complete. Click here to answer the next 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.