生成的包含卫兵:一次替代实用主义
介紹
在C ++中,沒有什么可以阻止程序員多次包含頭文件。 這可能會導(dǎo)致定義重復(fù),這是一個錯誤。 由于很難確保只將頭文件包含一次,因此常見的策略是僅對第一個包含計數(shù)進(jìn)行計數(shù)。 可以使用“包含保護(hù)”來完成,這是一小段預(yù)處理器邏輯,如下所示:
它是如何工作的?
在第一個include上, HEADER_HAS_BEEN_INCLUDED未定義,因此我們定義foo 。 在隨后的包含中,已定義HEADER_HAS_BEEN_INCLUDED ,因此我們僅跳過內(nèi)容。
例如,如果我們有此C ++文件:
然后它將擴(kuò)展為:
在預(yù)處理程序完成后,我們將得到以下結(jié)果:
這是慣用的方法,但是有一些限制:
那一次實(shí)用主義呢?
#pragma once旨在克服這些問題。 它是C ++編譯器的非標(biāo)準(zhǔn)功能,但得到了廣泛支持。 這個概念很簡單:任何包含#pragma once文件實(shí)際上只會被包含一次,即使程序員多次包含它。
#pragma once使用#pragma once ,我們的示例變?yōu)?#xff1a;
看起來不錯吧? 可悲的是, #pragma once帶來了許多問題。
根本原因是#pragma once涉及其中一些代碼的生活,而不是它的內(nèi)容 。 如果您可以通過多個路徑訪問同一文件的兩個副本,那么它將被包含兩次。 而且,如果您有兩條路徑看起來不同但實(shí)際上相同,那么編譯器可能不會發(fā)現(xiàn)這一點(diǎn)。 最重要的是,它不是標(biāo)準(zhǔn)的,因此編譯器實(shí)現(xiàn)不必尊重其語義。
可能的解決方法
#pragma once的問題#pragma once源于它在文件的位置而不是其內(nèi)容上起作用的事實(shí)。 如果我們只是使用內(nèi)容呢? (當(dāng)然,記錄每個標(biāo)題的所有內(nèi)容會很慢,但是我們可以通過記錄內(nèi)容的哈希值來進(jìn)行優(yōu)化)。
該過程將是:
1.包含頭文件時,對其進(jìn)行哈希處理
2.如果以前已經(jīng)看到過哈希,則忽略包含
3.否則,正常包含標(biāo)題
這將是一個可靠的解決方案,因?yàn)樗静魂P(guān)心文件所在的路徑,而只關(guān)心文件的內(nèi)容。
實(shí)施解決方法
將新命令添加到C ++標(biāo)準(zhǔn)將花費(fèi)大量時間,但是幸運(yùn)的是,我們可以使用腳本和預(yù)處理器來實(shí)現(xiàn)此邏輯。
基本思想是這樣的:
因此,例如此標(biāo)頭:
SHA-256哈希值為:
因此,生成的標(biāo)頭可能是:
盡管單個文件的轉(zhuǎn)換很簡單( Python腳本 ),但我們?nèi)匀恍枰芾磙D(zhuǎn)換過程。 我們需要確保:
- 為每個文件運(yùn)行轉(zhuǎn)換
- 新文件將自動轉(zhuǎn)換
- 刪除文件的轉(zhuǎn)換會自動刪除
- 僅在文件更改后才重新運(yùn)行轉(zhuǎn)換
- 獎勵:轉(zhuǎn)換可以安全地放入共享的網(wǎng)絡(luò)緩存中
使用Buck build ,我們可以輕松地將此邏輯編碼到項目的構(gòu)建腳本中。
讓我們從單個文件的構(gòu)建規(guī)則開始,然后進(jìn)行概括:
Buck中的genrule很像Make中的目標(biāo)。 我們定義輸入文件,輸出文件名和要執(zhí)行的命令。 該目標(biāo)使用我們的Python腳本來生成包含保護(hù),并在add.hpp上運(yùn)行它。 與Make不同,Buck將在輸入哈希中隔離并緩存該進(jìn)程。
現(xiàn)在我們只有一個文件,我們可以將流程推廣到n文件。 為此,我們制作了一個Python函數(shù),該genrule為給定的文件創(chuàng)建了一個genrule :
要獲取頭文件集,我們運(yùn)行一個glob表達(dá)式。 例如:
并將所有內(nèi)容整合在一起:
您可以在GitHub上找到完整的工作示例 。
現(xiàn)在,我們的頭文件可以一次編寫而無需包含保護(hù)或#pragma once :
Buck中的此設(shè)置非常適合與以下對象一起使用:
- 頭文件中的零樣板
- Buck會自動檢查新的頭文件,因此構(gòu)建始終是最新的
- Buck將刪除過時的頭文件
- 因?yàn)樗私饽繕?biāo)圖,所以Buck將并行生成標(biāo)頭
- Buck將緩存生成的頭,以便僅在需要時才計算
- 我們不再依賴人類的準(zhǔn)確性(包括防護(hù)措施)或非標(biāo)準(zhǔn)功能( #pragma once )
既然你在這里...
我們創(chuàng)建了Buckaroo ,以便更輕松地集成C ++庫。 如果您想嘗試一下,最好的起點(diǎn)是文檔 。 您可以瀏覽Buckaroo.pm上的現(xiàn)有軟件包,或在愿望清單上請求更多。
C ++依賴管理的方法,或者為什么我們構(gòu)建BuckarooC ++是一種不常見的語言,因?yàn)樗€沒有主要的程序包管理器(我們正在努力!)。 結(jié)果是…… hackernoon.com
From: https://hackernoon.com/generated-include-guards-an-alternative-to-pragma-once-31cc3dee6ce
總結(jié)
以上是生活随笔為你收集整理的生成的包含卫兵:一次替代实用主义的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android拍照,照片会自己旋转
- 下一篇: 宝宝成长季4天-我出生啦!