簡體   English   中英

這個僅標頭的庫如何防止鏈接程序問題?

[英]How does this header-only library guard against linker problems?

閱讀了這個問題之后,我以為我理解了所有內容,但是隨后我從一個流行的僅標頭庫中看到了這個文件

該庫使用#ifndef行,但是SO問題指出這不足以防止多個TU中的多個定義錯誤。

因此,以下條件之一必須為真:

  1. 可以通過SO問題中未描述的其他方式避免多個定義鏈接器錯誤。 也許圖書館使用的是其他SO問題中未提及的技術,值得進一步解釋。
  2. 該庫假設您不會在翻譯單元中包含其頭文件-這似乎很脆弱,因為健壯的庫不應該對用戶進行此假設。

我希望能對這種看似簡單的好奇心有所啟發。

當包含在多個翻譯單元中時,導致鏈接問題的標頭是一個(試圖)在包含它的每個源文件中定義某個對象 (不僅僅是一個明顯的例子,是一種類型)的標頭。

例如,如果您有類似以下內容: int f = 0; 在標頭中,然后每個包含該源文件的源文件都會嘗試定義f ,當您嘗試將目標文件鏈接在一起時,您會抱怨f多個定義。

此標頭中使用的“技術”很簡單:它不會嘗試定義任何實際對象。 相反,它包括一些typedef和一個相當大的類的定義-但不包括該類的任何實例或任何其他實例。 該類包括許多成員函數,但是它們都在函數定義內部定義,將其隱式定義為內聯函數(因此,不僅允許使用,而且要求在使用它們的每個翻譯單元中分別定義)。

簡而言之,標頭僅定義類型 ,而不是對象,因此當包含在鏈接在一起的多個源文件中時,沒有任何東西會導致鏈接器沖突。

如果標頭定義了項目,而不是僅僅聲明它們,則可以將其包含在多個翻譯單元(即cpp文件)中,並具有多個定義,從而導致鏈接器錯誤。

我使用了boost的單元測試框架,該框架僅是標題。 我僅在自己的一個cpp文件中包含一個指定的標頭,以使我的項目得以編譯。 但是我在其他cpp文件中包括其他單元測試標頭,這些標頭可能使用指定標頭中定義的項目。

標頭僅包括Boost C ++庫之類的庫, (大多數情況下)使用獨立模板,因此是在編譯時進行編譯的,不需要與二進制庫的任何鏈接(需要單獨編譯)。 永遠不需要鏈接的一種設計是絕佳的抓取力

模板是C ++中關於多個定義的特殊情況,只要它們相同即可。 請參閱C ++標准的“一個定義規則”部分:

一個類類型(第9章),枚舉類型(7.2),具有外部鏈接的內聯函數(7.1.2),類模板(第14章),非靜態函數模板(14.5.6)可以有多個定義。 ,類模板的靜態數據成員(14.5.1.3),類模板的成員函數(14.5.1.1)或在程序中未指定某些模板參數(14.7、14.5.5)的模板專門化,前提是每個定義出現在不同的翻譯單元中,並且定義滿足以下要求。 ....

然后是一系列條件,這些條件確保模板定義在翻譯單元之間相同。

此特定引用來自2014年工作草案第3.2節(“一個定義規則”)第6小節。

該頭文件確實可以包含在不同的源文件中,而不會引起“多個符號定義”錯誤。

發生這種情況的原因是,只要這些符號是弱符號或局部符號,就可以在不同的對象文件中使用多個名稱相同的符號。

讓我們仔細看看頭文件。 (可能)定義了一些類似於此helper對象:

static int const helper[] = {0,7,8,13};

包含此頭文件的每個翻譯單元都將具有此helper 但是,由於helperstatic ,因此具有內部鏈接,因此不會出現“多個符號定義”錯誤。 helper創建的符號將是本地的,鏈接器將很樂意將它們全部放入生成的可執行文件中。

頭文件還定義了類模板connection 但這也沒關系。 可以在不同的翻譯單元中多次定義類模板。

實際上,即使是常規的類類型也可以多次定義(我注意到您在注釋中已經對此進行了詢問)。 為成員函數創建的符號通常是弱符號。 同樣,弱符號不會導致“多個符號定義”錯誤,因為它們可以重新定義。 鏈接器將繼續用已經見過的名稱重新定義弱符號,直到每個成員函數只剩下一個符號。

在其他情況下,某些事物(例如內聯函數和枚舉)可以在不同的翻譯單元中定義多次(請參閱第3.2節)。 實現此目標的機制可能有所不同(請參閱類模板和內聯函數)。 但是一般規則是不要將具有全局鏈接的內容放在頭文件中。 只要遵循此規則,您實際上不太可能偶然發現多個符號定義問題。

是的,包括警衛隊與此無關。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM