"Effective C + +" 5th implementation-Reading notes

Source: Internet
Author: User

Chapter Review:

The 1th chapter of effective C + + makes himself accustomed to c++-reading notes

Effective C + + 2nd structure/destructor/assignment operation (1)-Reading notes

Effective C + + 2nd structure/destructor/assignment operation (2)-Reading notes

"Effective C + +" Chapter 3rd resource Management (1)-Reading notes

"Effective C + +" Chapter 3rd Resource Management (2)-Reading notes

"Effective C + +" 4th Chapter design and Declaration (1)-Reading notes

"Effective C + +" 4th Chapter design and Declaration (2)-Reading notes

"Effective C + +" 5th implementation-Reading notes

"Effective C + +" 8th custom new and delete-reading notes

Clause 26: Delay the occurrence of variable definitions whenever possible

When you define a variable of a class type, you consume a constructor and a destructor. If you end up not using this variable, you should avoid these costs.

You may wonder: how is it possible to define a variable without using it? Consider the following code:

 std::string  Encryptpassword (const  std::string  & password) { Span style= "color: #0000ff;"    >using  namespace   Std;     string   encrypted;  if  (Password.length () < Minimumpasswordlength) { throw  logic_error ( " password is too short  "  )    }        ...     return   encrypted;}  

Don't think about the meaning of the code first. If the IF statement is true, an exception is thrown, and the encrypted object still needs to consume a constructor and a destructor. So it's best to postpone the definition of encrypted until you really need it.

STD::stringEncryptpassword (ConstSTD::string&password) {    using namespacestd; if(Password.length () <minimumpasswordlength) {        ThrowLogic_error ("Password is too short")    }        stringEncrypted//put it in the back.    ...    returnencrypted;}

This code is not enough Nongsa (not understand the word). Because the encrypted object calls the default constructor, it will almost certainly be re-assigned. Examples are as follows:

void Encrypt (std::string& s); std::string encryptpassword (const std::string& password) {    ... string encrypted;            // put it in the back, considering the use of the definition          = password;        // re-assign value     Encrypt (encrypted);     return encrypted;}

A better approach is to skip the meaningless default constructor:

std::string encryptpassword (const std::string&    password) {... string encrypted (password);            // copy Constructor     Encrypt (encrypted);     return encrypted;}

So thereal meaning of "delaying as much as possible" is that you not only have to postpone the definition of the variable as much as possible until you use it, but you should postpone the definition of the variable until you give it an initial value . This avoids the unnecessary construction and destruction of objects and meaningless default constructors.

There is another situation in the loop, divided into the following two ways A, b which is better:

// procedure a Widget W;          for (int0; i < n; + +i)    {= depends on a value of I;    } // Procedure B  for (int0; i < n; + +i)    {= depends on a value of I;    }

The cost of procedure a: a constructor, a destructor, and n assignments; cost of Procedure B: N constructors and N destructors.

If the assignment cost is less than 1 constructs + 1 destructors, then the procedure A is more efficient, otherwise B is good. In addition the procedure a causes the Widget object scope to expand. So, the advice is: unless you explicitly know the cost of a few operations, then B is better.

remember to defer the occurrence of variable definitions whenever possible. This can increase the clarity of the program and improve the efficiency of the program.

Clause 27: Try to do less transformational action

C-style transformation (Legacy transformation) is as follows:

(T) expression;        // they mean the same thing. T (expression)

The 4 new types of transformation offered by C + + are as follows:

Const_cast<t>(expression) dynamic_cast<T>(expression) reinterpret_cast<t >(expression) static_cast<T> (expression)

Generally speaking, the new transformation is better. Perhaps the most common place for legacy transformations is when you call the explicit constructor to pass an object to the function. Examples are as follows:

class widget{public:    explicit Widget (int  size);}; void dosomework (const widget& W);d osomework (Widget ());                    // C's Function style dosomework (static_cast<Widget> ());    // C + + new style

Any type conversion, either an explicit conversion through a transformation operation or an implicit conversion through the compiler, often causes the compiler to generate code that executes at run time.

Here's a transformation code that's a bit confusing:

classwindow{ Public: Window (intn =0): M (n) {}Virtual voidonResize () {m=Ten; }    intm;};classSpecialwindow: Publicwindow{ Public:    Virtual voidonResize () {static_cast<Window> (* This). OnResize (); }};intMain () {Specialwindow W1; cout<< w1.m << Endl;//Output 0w1.onresize (); cout<< w1.m << Endl;//Output 0    return 0;}

Two copies of the output are all 0. Don't doubt,static_cast<window> (*this). OnResize (); indeed, the onResize () function of class Window is called, but the key is that the result of the transformation is a copy of (*this), not the object itself.

If you still need to call the class window version of the onresize () function, take off the transformation.

class  Public window{public:    virtualvoid  onResize ()    {        Window::o Nresize ();    }};

The cost of dynamic_cast is high, and one reason to need it is to execute the derived class function on a class object that you have identified as derived, but you only have a pointer or reference to base.

Please remember:

(1) if possible, avoid transformation, especially in the efficiency-oriented code to avoid dynamic_cast. If you have a design that requires transformational action, try to develop an alternative design that doesn't need to be transformed.

(2) if the transformation is necessary, try to hide it behind a function, and the customer can then invoke the function without having to put the transformation inside their own code.

(3) Preferential use of C + + style of transformation, because it is easy to identify and classification.

Clause 28: Avoid returning handles points to the inner component of the object

Handles includes pointers, references, and iterators. Use examples directly to illustrate:

classPoint//represents a "point"{ Public: Point (intXinty); ..voidSetX (intnewval); voidSety (intnewval);}structrectdata{Point ULHC; //represents the upper-left corner coordinatePoint LRHC;//represents the lower right corner coordinates};classrectangle{ Public: Point& Upperleft ()Const{returnpdata->ulhc; }//returns the upper-left coordinatepoint& Lowerright ()Const{returnpdata->lrhc; }//return to the lower-right corner coordinates};

Rectangle class Design Two member functions Upperleft (), Lowerright () returns the upper-left and lower-right coordinates are necessary. But both of these functions are const, stating that it is intended only to be viewed by the user, not to allow the user to modify the coordinates. But the customer does this:

Point Coord1 (00); Point Coord2 (+); Const Rectangle Rec (coord1, coord2); Rec.upperleft (). SetX (+);                // Upper left corner coordinates changed to (50,0)

It does change the coordinate value, although point is private data. The implication of this is that the encapsulation of a member variable is at most equal to the level of access that returns its reference function . Although point is private, the actual effect is public.

Modifying the version is also simple:

class rectangle{public:    constconstreturn pdata->ulhc;}            // returns the const    of the upper-left corner coordinate Const Const return pdata->lrhc; }            // returns the lower-right coordinate of the const};

Another point that handles points to may no longer exist after the return of something . To illustrate:

class guiobject {...}; Const Rectangle BoundingBox (const guiobject& obj); // This is called by the client as follows Guiobject *PGO; Const Point *pupperleft = & (BoundingBox (*PGO). Upperleft ());

The call to BoundingBox (*PGO) will produce a temporary rectangle object that calls Upperleft () on this object to return the upper-left coordinate of the temporary object, and then the temporary object is refactored so that pupperleft points to something that does not exist.

Keep in mind: Avoid returning handles (including references, pointers, and iterators) to the inner object. Adherence to this clause increases encapsulation, helps the const member function behave like a const, and reduces the likelihood of handles pointing to something that does not exist.

"Effective C + +" 5th implementation-Reading notes

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.