日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

减少C++代码编译时间的方法

發布時間:2025/3/15 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 减少C++代码编译时间的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

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

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

2.?刪除不必要的一大堆私有成員變量,轉而使用?"impl"?方法

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

?

為了講清楚這3點,還是舉個實例比較好,這個實例我會一步一步的改進(因為我也是一點一點摸索出來了,如果哪里說錯了,?你就放心的噴吧,我會和你在爭論到底的,呵呵)

現在先假設你找到一個新工作,接手以前某個程序員寫的類,如下

// old.h: 這就是你接收的類// #include <iostream>#include <ostream>#include <list> // 5 個 分別是file , db, cx, deduce or error , 水平有限沒有模板類// 只用 file and cx 有虛函數.#include "file.h" // class file#include "db.h" // class db#include "cx.h" // class cx#include "deduce.h" // class deduce#include "error.h" // class errorclass 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); }

  

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

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

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

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

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

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

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

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

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

除此之外,要是你說這個函數要操作ostream?對象,?那還是需要#include?<ostream>?,?你只說對了一半,?的確,?這個函數要操作ostream?對象,?但是請看他的函數實現,

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

?

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

?

// old.h: 這就是你接收的類// #include <iosfwd> //新替換的頭文件#include <list> // 5 個 分別是file , db, cx, deduce or error , 水平有限沒有模板類// 只用 file and cx 有虛函數.#include "file.h" // class file , 作為基類不能刪除,刪除了編譯器就不知道實例化old 對象時分配多大的空間了#include "db.h" // class db, 作為基類不能刪除,同上#include "cx.h" // class cx#include "deduce.h" // class deduce// error 只被用做參數和返回值類型, 用前向聲明替換#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 是模版類型,既不是函數參數類型也不是函數返回值類型,所以cx.h 頭文件不能刪除deduce deduce_d_; // deduce 是類型定義,也不刪除他的頭文件}; inline std::ostream& operator<<( std::ostream& os,const old& old_val ){ return old_val.print(os); }

?

  

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

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

?

2.?刪除不必要的一大堆私有成員變量,轉而使用?"impl"?方法

  2.1.使用?"impl"?實現方式寫代碼,減少客戶端代碼的編譯依賴

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

?

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

?

  

改寫成這樣:

// file old.hclass old {//公有和保護成員// public and protected membersprivate:class oldImpl* pimpl_;// 替換原來的所有私有成員變量為這個impl指針,指針只需要前向聲明就可以編譯通過,這種寫法將前向聲明和定義指針放在了一起, 完全可以。//當然,也可以分開寫// a pointer to a forward-declared class};// file old.cppstruct oldImpl {//真正的成員變量隱藏在這里, 隨意變化, 客戶端的代碼都不需要重新編譯// private members; fully hidden, can be// changed at will without recompiling clients};

  

不知道你看明白了沒有,?看不明白請隨便寫個類試驗下,我就是這么做的,當然凡事也都有優缺點,下面簡單對比下:

?

?

?

使用impl?實現類

不使用impl實現類

優點

類型定義與客戶端隔離,?減少#include?的次數,提高編譯速度,庫端的類隨意修改,客戶端不需要重新編譯

直接,簡單明了,不需要考慮堆分配,釋放,內存泄漏問題

缺點

對于impl的指針必須使用堆分配,堆釋放,時間長了會產生內存碎片,最終影響程序運行速度,?每次調用一個成員函數都要經過impl->xxx()的一次轉發

庫端任意頭文件發生變化,客戶端都必須重新編譯

?

改為impl實現后是這樣的:

// 只用 file and cx 有虛函數.#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.?刪除不必要的類之間的繼承

? ? ? ? ?面向對象提供了繼承這種機制,但是繼承不要濫用,?old?class?的繼承就屬于濫用之一,?class?old?繼承file?和?db?類,?繼承file是公有繼承,繼承db?是私有繼承

,繼承file?可以理解,?因為file?中有虛函數,?old?要重新定義它,?但是根據我們的假設,?只有file?和?cx?有虛函數,私有繼承db?怎么解釋?!?那么唯一可能的理由就是:

通過?私有繼承—讓某個類不能當作基類去派生其他類,類似Javafinal關鍵字的功能,但是從實例看,顯然沒有這個用意,?所以這個私有繼承完全不必要,?應該改用包含的方式去使用db類提供的功能,?這樣就可以

"db.h"頭文件刪除,?把db?的實例也可以放進impl類中,最終得到的類是這樣的:

?

// 只用 file and cx 有虛函數.#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_; };

?

  

小結一下:

這篇文章只是簡單的介紹了減少編譯時間的幾個辦法:

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

2.?刪除不必要的一大堆私有成員變量,轉而使用?"impl"?方法

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

?

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

?

轉載于:https://www.cnblogs.com/misserwell/p/4343927.html

總結

以上是生活随笔為你收集整理的减少C++代码编译时间的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。