中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

減少C++代碼編譯時(shí)間的方法

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

c++?的代碼包含頭文件和實(shí)現(xiàn)文件兩部分,?頭文件一般是提供給別人(也叫客戶)使用的,?但是一旦頭文件發(fā)生改變,不管多小的變化,所有引用他的文件就必須重新編譯,編譯就要花時(shí)間,假如你做的工程比較大(比如二次封裝chrome這類的開發(fā)),重新編譯一次的時(shí)間就會(huì)浪費(fèi)上班的大部分時(shí)間,這樣干了一天挺累的,?但是你的老板說你沒有產(chǎn)出,結(jié)果你被fired,?是不是很怨啊,?如果你早點(diǎn)看到這段文章,你就會(huì)比你的同事開發(fā)效率高那么一些,那樣被fired就不會(huì)是你了,你說這篇文章是不是價(jià)值千金!開個(gè)玩笑?:)

言歸正傳,怎樣介紹編譯時(shí)間呢,?我知道的就3個(gè)辦法:

  1. 刪除不必要的#include,替代辦法?使用前向聲明?(forward?declared?)
  2. 刪除不必要的一大堆私有成員變量,轉(zhuǎn)而使用?”impl”?方法
  3. ?刪除不必要的類之間的繼承

為了講清楚這3點(diǎn),還是舉個(gè)實(shí)例比較好,這個(gè)實(shí)例我會(huì)一步一步的改進(jìn)(因?yàn)槲乙彩且稽c(diǎn)一點(diǎn)摸索出來了,如果哪里說錯(cuò)了,?你就放心的噴吧,我會(huì)和你在爭論到底的,呵呵)

現(xiàn)在先假設(shè)你找到一個(gè)新工作,接手以前某個(gè)程序員寫的類,如下

//? old.h: 這就是你接收的類
?????//
?????#include <iostream>
?????#include <ostream>
?????#include <list>

?????// 5 個(gè) 分別是file , db, cx, deduce or error , 水平有限沒有模板類
?????// 只用 file and cx 有虛函數(shù).
?????#include "file.h"? // class file
?????#include "db.h"? // class db
?????#include "cx.h"? // class cx
?????#include "deduce.h"? // class deduce
?????#include "error.h"? // class error

?????class old : public file, private db {
?????public:
??????????old( const cx& );
???????db? get_db( int, char* );
???????cx? get_cx( int, cx );
???????cx& fun1( db );
???????error? fun2( error );
???????virtual std::ostream& print( std::ostream& ) const;
?????private:
???????std::list<cx> cx_list_;
???????deduce?????? deduce_d_;
?????};
????????inline std::ostream& operator<<( std::ostream& os,const old& old_val )
???????{ return old_val.print(os); }

這個(gè)類看完了,?如果你已經(jīng)看出了問題出在哪里,?接下來的不用看了,?你是高手,?這些基本知識(shí)對(duì)你來說太小兒科,要是像面試時(shí)被問住了愣了一下,請接著看吧

先看怎么使用第一條:?刪除不必要的#include

這個(gè)類引用?5個(gè)頭文件,?那意味著那5個(gè)頭文件所引用的頭文件也都被引用了進(jìn)來,?實(shí)際上,?不需要引用5?個(gè),只要引用2個(gè)就完全可以了

1.刪除不必要的#include,替代辦法?使用前向聲明?(forward?declared?)

1.1刪除頭文件?iostream,?我剛開始學(xué)習(xí)c++?時(shí)照著《c++?primer》?抄,只要看見關(guān)于輸入,輸出就把?iostream?頭文件加上,?幾年過去了,?現(xiàn)在我知道不是這樣的,?這里只是定義輸出函數(shù),?只要引用ostream?就夠了

1.2.ostream頭文件也不要,?替換為?iosfwd?,?為什么,?原因就是,?參數(shù)和返回類型只要前向聲明就可以編譯通過,?在iosfwd?文件里?678行(我的環(huán)境是vs2013,不同的編譯環(huán)境具體位置可能會(huì)不相同,但是都有這句聲明)?有這么一句

typedef?basic_ostream<char,?char_traits<char>?>?ostream;

inline?std::ostream&?operator<<(?std::ostream&?os,const?old&?old_val?)

{?return?old_val.print(os);?}

除此之外,要是你說這個(gè)函數(shù)要操作ostream?對(duì)象,?那還是需要#include?<ostream>?,?你只說對(duì)了一半,?的確,?這個(gè)函數(shù)要操作ostream?對(duì)象,?但是請看他的函數(shù)實(shí)現(xiàn),

里面沒有定義一個(gè)類似?std::ostream?os,?這樣的語句,話說回來,但凡出現(xiàn)這樣的定義語句,?就必須#include?相應(yīng)的頭文件了?,因?yàn)檫@是請求編譯器分配空間,而如果只前向聲明?class?XXX;?編譯器怎么知道分配多大的空間給這個(gè)對(duì)象!

看到這里,?old.h頭文件可以更新如下了:

//? old.h: 這就是你接收的類
?????//
?????#include <iosfwd>? //新替換的頭文件
?????#include <list>

?????// 5 個(gè) 分別是file , db, cx, deduce or error , 水平有限沒有模板類
?????// 只用 file and cx 有虛函數(shù).
?????#include "file.h"? // class file? , 作為基類不能刪除,刪除了編譯器就不知道實(shí)例化old 對(duì)象時(shí)分配多大的空間了
?????#include "db.h"? // class db, 作為基類不能刪除,同上
?????#include "cx.h"? // class cx
?????#include "deduce.h"? // class deduce
?????// error 只被用做參數(shù)和返回值類型, 用前向聲明替換#include? "error.h"?
?????class error;

?????class old : public file, private db {
?????public:
??????????old( const cx& );
???????db? get_db( int, char* );
???????cx? get_cx( int, cx );
???????cx& fun1( db );
???????error? fun2( error );
???????virtual std::ostream& print( std::ostream& ) const;
?????private:
???????std::list<cx> cx_list_; //? cx 是模版類型,既不是函數(shù)參數(shù)類型也不是函數(shù)返回值類型,所以cx.h 頭文件不能刪除
???????deduce?????? deduce_d_; //? deduce 是類型定義,也不刪除他的頭文件
?????};
????????inline std::ostream& operator<<( std::ostream& os,const old& old_val )
???????{ return old_val.print(os); }

到目前為止,?刪除了一些代碼,?是不是心情很爽,據(jù)說看一個(gè)程序員的水平有多高,?不是看他寫了多少代碼,而是看他少寫了多少代碼。

如果你對(duì)C++?編程有更深一步的興趣,?接下來的文字你還是會(huì)看的,再進(jìn)一步刪除代碼,?但是這次要另辟蹊徑了

2.?刪除不必要的一大堆私有成員變量,轉(zhuǎn)而使用?”impl”?方法

2.1.使用?”impl”?實(shí)現(xiàn)方式寫代碼,減少客戶端代碼的編譯依賴

impl?方法簡單點(diǎn)說就是把?類的私有成員變量全部放進(jìn)一個(gè)impl?類,?然后把這個(gè)類的私有成員變量只保留一個(gè)impl*?指針,代碼如下

// file old.h
?????class old {
????????//公有和保護(hù)成員
???????// public and protected members
?????private:
?????//私有成員, 只要任意一個(gè)的頭文件發(fā)生變化或成員個(gè)數(shù)增加,減少,所有引用old.h的客戶端必須重新編譯
???????// private members; whenever these change,
???????// all client code must be recompiled
?????};

改寫成這樣:

// file old.h
?????class old {
?????//公有和保護(hù)成員
???????// public and protected members
?????private:
???????class oldImpl* pimpl_;
???????//? 替換原來的所有私有成員變量為這個(gè)impl指針,指針只需要前向聲明就可以編譯通過,這種寫法將前向聲明和定義指針放在了一起, 完全可以。
???????//當(dāng)然,也可以分開寫
?????????// a pointer to a forward-declared class
?????};

?????// file old.cpp
?????struct oldImpl {
?????//真正的成員變量隱藏在這里, 隨意變化, 客戶端的代碼都不需要重新編譯
???????// private members; fully hidden, can be
???????// changed at will without recompiling clients
?????};

不知道你看明白了沒有,?看不明白請隨便寫個(gè)類試驗(yàn)下,我就是這么做的,當(dāng)然凡事也都有優(yōu)缺點(diǎn),下面簡單對(duì)比下:

使用impl?實(shí)現(xiàn)類 不使用impl實(shí)現(xiàn)類
優(yōu)點(diǎn) 類型定義與客戶端隔離,?減少#include?的次數(shù),提高編譯速度,庫端的類隨意修改,客戶端不需要重新編譯 直接,簡單明了,不需要考慮堆分配,釋放,內(nèi)存泄漏問題
缺點(diǎn) 對(duì)于impl的指針必須使用堆分配,堆釋放,時(shí)間長了會(huì)產(chǎn)生內(nèi)存碎片,最終影響程序運(yùn)行速度,?每次調(diào)用一個(gè)成員函數(shù)都要經(jīng)過impl->xxx()的一次轉(zhuǎn)發(fā) 庫端任意頭文件發(fā)生變化,客戶端都必須重新編譯

改為impl實(shí)現(xiàn)后是這樣的:

// 只用 file and cx 有虛函數(shù).
?????#include "file.h"?
?????#include "db.h"?
?????class cx;
?????class error;

?????class old : public file, private db {
?????public:
??????????old( const cx& );
???????db? get_db( int, char* );
???????cx? get_cx( int, cx );
???????cx& fun1( db );
???????error? fun2( error );
???????virtual std::ostream& print( std::ostream& ) const;
?????private:
class oldimpl* pimpl; //此處前向聲明和定義
??????};
????????inline std::ostream& operator<<( std::ostream& os,const old& old_val )
???????{ return old_val.print(os); }

//implementation file old.cpp
class oldimpl{
std::list<cx> cx_list_;
deduce??????? dudece_d_;
};

3.?刪除不必要的類之間的繼承

面向?qū)ο筇峁┝死^承這種機(jī)制,但是繼承不要濫用,?old?class?的繼承就屬于濫用之一,?class?old?繼承file?和?db?類,?繼承file是公有繼承,繼承db?是私有繼承

,繼承file?可以理解,?因?yàn)閒ile?中有虛函數(shù),?old?要重新定義它,?但是根據(jù)我們的假設(shè),?只有file?和?cx?有虛函數(shù),私有繼承db?怎么解釋?!?那么唯一可能的理由就是:

通過?私有繼承—讓某個(gè)類不能當(dāng)作基類去派生其他類,類似Java里final關(guān)鍵字的功能,但是從實(shí)例看,顯然沒有這個(gè)用意,?所以這個(gè)私有繼承完全不必要,?應(yīng)該改用包含的方式去使用db類提供的功能,?這樣就可以

把”db.h”頭文件刪除,?把db?的實(shí)例也可以放進(jìn)impl類中,最終得到的類是這樣的:

// 只用 file and cx 有虛函數(shù).
?????#include "file.h"?
?????class cx;
?????class error;
?????class db;
?????class old : public file {
?????public:
??????????old( const cx& );
???????db? get_db( int, char* );
???????cx?? get_cx( int, cx );
???????cx& fun1( db );
???????error? fun2( error );
???????virtual std::ostream& print( std::ostream& ) const;
?????private:
???????class oldimpl* pimpl; //此處前向聲明和定義
??????};
????????inline std::ostream& operator<<( std::ostream& os,const old& old_val )
???????{ return old_val.print(os); }

//implementation file old.cpp
class oldimpl{
std::list<cx> cx_list_;
deduce??????? dudece_d_;
};

小結(jié)一下:

這篇文章只是簡單的介紹了減少編譯時(shí)間的幾個(gè)辦法:

1.?刪除不必要的#include,替代辦法?使用前向聲明?(forward?declared?)

2.?刪除不必要的一大堆私有成員變量,轉(zhuǎn)而使用?”impl”?方法

3.?刪除不必要的類之間的繼承

這幾條希望對(duì)您有所幫助,?如果我哪里講的不夠清楚也可以參考附件,哪里有完整的實(shí)例,也歡迎您發(fā)表評(píng)論,?大家一起討論進(jìn)步,哦不,加薪。?呵呵,在下篇文章我將把impl實(shí)現(xiàn)方式再詳細(xì)分析下,期待吧…

標(biāo)簽: 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:C程序運(yùn)行時(shí)內(nèi)存結(jié)構(gòu)分析

下一篇:愛上Java和JVM的10大理由