GURU of the week # 7: Compile-Time Dependences

zhaozj2021-02-08  265

Author: Herb Sutter Translator: plpliuly

/ * This article is a 77 of the GotW (GURU of the Week) series of self-entertainment translations, the original copyright is the author of Herb Sutter (the famous C expert, "Exceptional C " author). The translation of this article did not have the consent of the original author, only for learning discussion. - Translator * /

# 7 Compile-Time Dependencies Difficulty: 7/10 Many people use #include with #include when writing C programs, contains some unnecessary headers. Are you also like this? See what we have to discuss below.

problem:

[Reminder: This problem will be difficult than it looks. Also please pay attention to the comments in the program. ] Contains too much unnecessary header files will seriously grow program build time, especially in a header file containing many source files, That too much header file.

In the header file below, which #include statement can be removed immediately? Second, which #include statement can be removed after proper adjustment? (You can't change the public interface of Class X and Class Y; that is, any changes you do cannot affect customer code).

// gotw007.h (importation file is gotw007.cpp) // #include "ah" // class a #include "bh" // class b #include "ch" // class c #include "dh" // class D // (NOTE: ONLY A and C Have Virtual Functions) #include #include #include #include #include

Class x: public a {public: x (const c &); d function1 (int, char *); d function1 (int, c); b & function2 (b); void function3 (std :: wostringstream &); std :: ostream & Print: std :: string name_; std :: list clist_; d_;}; std :: ostream & operator << (std :: ostream & os, const x) { Return X.Print (OS);

Class Y: Private B {Public: c Function4 (a); private: std :: list alist_;};

answer

First, see which headers don't have to include it completely. 1. We can immediately remove: -ioStream, because despite the use of streams, there is no special thing in any iosteam. -OSTEAM and SSTREAM, because parameters and return values ​​are only available forward-declared). So just include iOSFWD. (Note There is no corresponding "stringfwd" or "listfwd" standard library header file; iOSFWD is the code that is compatible with the existing use of non-template STREAM subsystems) We cannot immediately remove the head The files are: -ah: Because A is the base class of X - BH: B is y's base class -Ch: Because many existing compiler requirements know the definition of C when instantiation List (in the later This should be all correct in the compiler version) -DH: List and string, because the X needs to know the size of D and String objects, and x and y need to know the List of the object. Then, let's see which headers can remove after proper adjustment: 2. We can use PIMPL_ to use PIMPL_ to use PIMPL_ to go to DH, List, and String (that is, private parts use pointers to implement objects, implement objects are forward-declared), as this X and Y doesn't need to know D and List, String size information. This also makes we do not need to include C.h because the objects in x :: clist_ are only as parameters or return values. Important Tip: Defined as an operator of the inline type << You can remain inlined and using the OSTREAM type parameters, although Ostream has not been defined! This is because you only need the definition of parameters when you want to call the member function, and when you just need to use an object as a parameter of the function, you don't need to know the definition of the object.

Finally, see if you can continue to adjust to remove more header files: 3. Note that B is the private base class of Y and B has no virtual functions, we can remove B.H. The main reason for typically selecting private inheritance without selecting class aggregation or inclusive (nested classes) is to redefine the virtual function of the base class. Therefore, this should be changed to Yes having a B type member variable instead of inheriting from the Class B. In order to remove B.H, this member variable should be a hidden PIMPL_ part of Y. [Recommendation] Try to use PIMPL_ (which is pointing to implementation) will be separated from the customer code. The following text is extracted from the code specification of the GotW: - Package and Isolation - Avoid direct definition private members directly in the category state - use a non-transparent pointer to "struct XXXXIMPL * PIMPL_" to store private members (including private Member variables and members functions), such as Class Map {private: struct mapimpl * pimpl _;} (lakos96: 398-405; meyer92: 111-116; murray93: 72-74) 4. Currently we can't do any action against AH Because A is used to do X's public base class, and A has a virtual member function, so it is necessary to know or use this IS-A relationship in the customer code. However, notice that X and Y are simply not correlated, we can separate the definitions of X and Y to two different header files (assuming this header file is changed to a stub that includes XH and YH, so there is no need to change Existing code). In this case, at least y.h does not need to include A.h because it is only used as a function parameter, which is not required. Comprehensively synthesize the above content, we can get the following more information of the header file: file: // ---------------------------- ----------------------------------- // New file xh: only two incrudes! // #include " AH "// Class a #include

Class C; Class D; Class B; // Translator

Class x: public a {public: x (const c &); d function1 (int, char *); d function1 (int, c); b & function2 (b); void function3 (std :: wostringstream &); std :: ostream & Print (std :: ostream &) const; private: class ximpl * pimpl_;};

Inline std :: ostream & operator << (std :: ostream & os, const x) {return x.print (OS);} // NOTE: THIS DOES NOT Require Ostream's Definition!

File: // ---------------------------------------------- ----------------- // New file yh: zero incrudes! // Class A; Class C;

Class y {public: c function4 (a); private: class yimpl * pimpl_;}; file: // -------------------------- ------------------------------------- // Gotw007.h is now Just a Compatibility Stub with Two Lines, and // pulls inly two extra secondary inclus (through xh) // #include "xh" #include "yh"

File: // ---------------------------------------------- ----------------- // new structures in gotw007.cpp ... Note That the impl objects // Will Be.com and delete'd By the x / y dtors // and x / y member functions Will Access The Data THROUGH THEIR / / PIMPL_ POINTERS // Struct XIMPL // Yes, this can be called "even {// thing the forward-decl sign" Class "std :: string name_; std :: list clist_; d_;}

Struct Yimpl {std :: list alist_; b b_;}

As you can see from the above header files, the customer code (source file) using X simply includes AH and iostwd; if you do not change the customer code, the customer code that uses Y is only needed to include AH and IOSFWD, if in the future Using Y's Customer Code Update will contain GOTW007.H to contain YH, the Y's customer code does not need to include any other header files for use Y. Compare the original header file, this is a big improvement!

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

New Post(0)