2015-11-03 88 views
3

當某些C++實體(如結構,類或函數)被聲明爲模板時,爲所述實體提供的定義僅爲必須實例化的藍色打印。C++模板:模板實例是內聯的嗎?性能有缺點嗎?

由於模板實體必須在聲明時定義(通常是頭文件),所以我有這個概念,我試圖說服自己是錯的,當模板實例化後,它會由編譯器內聯。我想問問這是否是這樣?

question的答案引起了我的懷疑,當我讀到的段落:

「模板可導致慢編譯時間和可能更大 可執行文件,尤其是年紀較大的編譯器。」

由於模板必須實例化,但爲什麼「可能更大的可執行文件」更慢,編譯時間更慢?這應該以什麼方式解釋?我應該把它解釋爲'許多函數是內聯的',或者'如果有很多模板實例化,可執行文件的大小就會增加,這就是同一個模板被很多不同的類型實例化,這會導致同一個實體的多個副本出現' ?

在後一種情況下,較大的可執行文件大小是否會導致軟件運行速度較慢,因爲需要將更多代碼加載到內存中,這會導致代價很高的分頁?

此外,由於這些問題也有些依賴於編譯器,所以我對Visual C++編譯器感興趣。關於大多數編譯器所做的一般性回答也提供了良好的洞察力。

預先感謝您。

+5

您可以擁有更多代碼的一個原因是每個模板類型都是它自己的類型。所以你所有的'Foo '的代碼必須重複'Foo ' – NathanOliver

+0

@NathanOliver好吧,正如我現在所瞭解的,最新的鏈接器實現(g ++ 5.x)能夠合併相同的生成的實例化代碼。 –

+1

@πάνταῥεῖ你能提供一個鏈接嗎?這聽起來很有趣。 – bolov

回答

3

由於,當它被宣佈爲模板實體必須定義的事實(這通常是頭文件)

事實並非如此。您可以分別聲明和定義模板類,方法和函數,就像您可以使用其他類,方法和函數一樣。

我有一個概念,我試圖說服自己是錯的,當模板被實例化後,它會被編譯器內聯。我想問問這是否是這樣?

其中一些可能是或全部或不是全部。編譯器會做它認爲最好的。

由於模板必須實例化,爲什麼「可能更大的可執行文件」更慢,編譯時間更慢?這應該以什麼方式解釋?

它可以用多種方式解釋。以同樣的方式,一瓶阿斯匹林含有警告「可能會導致<插入副作用在這裏>」。

我應該解釋爲「很多內聯函數」或「可執行文件的大小增加時,如果有許多模板實例,即同一模板實例有很多不同的類型,這將導致的多個副本相同的實體在那裏'?

您將不會有同一個實體的多個副本 - 編譯器套件有責任看到這一點。即使方法是內聯,該方法的實際地址:

  1. 始終存在,並
  2. 時由多個編譯單元中引用相同的地址。

您可能發現的是,您開始創建比預期更多的類型。例如std::vector<int>是與std::vector<double>完全不同的類型。 foo<X>()是與foo<Y>()不同的功能。程序中的類型和函數定義的數量可以快速增長。

在後一種情況下,較大的可執行文件大小是否會導致軟件運行速度較慢,因爲必須將更多的代碼加載到內存中才能導致代價較高的分頁?

過度的尋呼,可能不是。過度的緩存未命中,很可能。通常情況下,優化較小的代碼是實現良好性能的一個很好的策略(在某些情況下,例如,當數據很少被訪問,並且全部在高速緩存中時)。

+1

值得一提的是,_inlining_僅僅是編譯器在鏈接階段所做的決定。 –

+0

我認爲你會混淆內聯(編譯器決定)和合並COMDAT(鏈接器責任) –

0

它們是否內聯總是由編譯器決定。非內聯模板實例化爲所有類似實例共享。

所以很多翻譯單元都希望做一個Foo<int>將共享Foo實例化。顯然,如果Foo<int>是一個函數,並且編譯器決定在每種情況下內聯它,那麼代碼將重複。但是內聯的選擇是因爲這樣做的優化看起來很可能優於函數調用。

從技術上講,可能是是模板導致執行速度較慢的一種情況。我使用的軟件具有超緊密的內部循環,因此我們進行了大量的性能測量。我們使用了許多模板函數和類,與手動編寫代碼相比,它還沒有顯示出降級。

我不能肯定,但我認爲你必須有在模板的情況: - 產生的非聯的代碼 - 這樣做的多個實例 - 本來是一個手寫功能 - 手寫函數不會導致運行時間受到一個函數的懲罰(即:沒有隱式轉換涉及運行時檢查)

然後有可能您有一種情況,即單手寫函數適合CPU的指令緩存但多個模板實例化沒有。

+0

當我幾年前測試,因爲不良引起的內聯選擇嚴重的性能問題ICC,GCC和MSVC,個個有這些問題,所有這些問題都是直接由於內聯的自頂向下的設計。由於內聯而導致性能災難的具體情況各不相同,但都有。首先內嵌一個不應該內聯的大模板函數。將內容嵌入到內容中,然後失敗(由於自上而下的限制),以便內嵌真正需要內聯的內容。 – JSF

+0

@JSF夠公平的。我無法說出你的經歷。我們在基於CPU的渲染器上工作,所以任何緩存缺失都會大幅降低性能。然而,我們並不傾向於製作大型功能模板,也不會嵌套太深的層次。我們的問題(奇怪)並不是它在內聯時內聯,而是內聯失效。在這方面,MSVC似乎早於其他編譯器放棄。 – qeadz