Чи більш ефективними є бібліотеки, призначені лише для заголовків?


48

Припущення

  1. Однією з переваг бібліотек, призначених лише для заголовків для C ++, є те, що їх не потрібно складати окремо.

  2. В C і C ++ inlineмає сенс лише, якщо функція визначена у файлі заголовка *.

  3. Традиційно в C, .c / .h використовується макет, де заголовок представляє мінімальний публічний інтерфейс блоку перекладу. Аналогічно .cpp / hpp.

Питання

Чи в основному бібліотеки, що мають лише заголовки, більш ефективні для коду та часу виконання, ніж традиційні верстки? Якщо так, то це через обширних вкладених чи інших оптимізацій?

* - визначення функції в заголовку дозволяє компілятору бачити реалізацію під час компіляції будь-якого блоку перекладу і практично робить можливим вбудований код


2
Ви здивуєтеся, наскільки багато сучасних C ++ лінкерів (GCC, MSVC, ICC тощо) можуть вбудовувати код у окремі одиниці перекладу. Я б сказав, що "взагалі немає" з точки зору ефективності, враховуючи кількість разів оптимізація лінкерів, оскаржував мої сподівання і вдається все-таки вбудувати (це виключає контексти dylib, де вбудований заголовок або надання реалізації в окремій статично пов'язаній бібліотеці може допомогти) . І все ж бібліотеки, призначені лише для заголовків, за умови, що вони стабільні як в інтерфейсі, так і в реалізації, можуть бути сексуальними через те, наскільки легко їх можна розгорнути в нових проектах.

1
Я не знаю, що це заслуговує повної відповіді, але однією з величезних переваг шаблонів лише заголовків є простота встановлення та використання: Завантажте, #include "lib.h (pp)", зроблено.
WeRelic

Відповіді:


44

Однією з переваг бібліотек, призначених лише для заголовків для C ++, є те, що їх не потрібно складати окремо

Ні, це не є перевагою, а навпаки - основну частину бібліотеки потрібно збирати так часто, як тільки вона потрапляє, а не один раз. Це, як правило, збільшить час компіляції. Однак якщо ви маєте на увазі переваги, перелічені тут у Вікіпедії : у цій статті йдеться про зменшення адміністративних витрат на весь процес збирання, упаковки та розгортання.

В In і C ++ вбудований має сенс лише у тому випадку, якщо функція визначена у файлі заголовка *

Це залежить від системи компілятора / лінкера, але я думаю, для більшості компіляторів C і C ++ це правда.

Традиційно в C, .c / .h використовується макет, де заголовок представляє мінімальний публічний інтерфейс блоку перекладу. Аналогічно .cpp / hpp.

Це здебільшого правильно. Заголовки класів C ++ часто містять більше, ніж мінімальний публічний інтерфейс - вони зазвичай містять також багато приватних матеріалів. Щоб пом'якшити це, використовуються такі речі, як ідіома PIMPL . Це щось на кшталт "протилежного" бібліотеці, що використовується лише в заголовку, вона намагається мінімізувати необхідний вміст заголовка.

Але щоб відповісти на ваше головне питання: це компроміс. Чим більше код бібліотеки вкладається у файли заголовків, тим більше у компілятора є шанс на оптимізацію коду за швидкістю (якщо це дійсно відбувається, або якщо збільшення помітне, це зовсім інше питання). З іншого боку, занадто багато коду в заголовках збільшує час компіляції. Особливо у великих проектах на C ++ це може стати серйозною проблемою, див. «Дизайн програмного забезпечення великого масштабу» Джона Лакоса - хоча книга дещо застаріла, і деякі проблеми, описані там, вирішуються сучасними укладачами, загальними ідеями / рішення все ще діють.

Зокрема, коли ви не використовуєте стабільну бібліотеку (третьої сторони), але під час проекту розробляєте власні бібліотеки, час компіляції стає очевидним. Кожен раз, коли ви щось змінюєте у вікні, ви повинні змінювати файл заголовка, що спричинить перекомпіляцію та зв’язок усіх залежних одиниць.

ІМХО популярність шаблонів лише для заголовків обумовлена ​​популярністю мета-програмування шаблонів. Для більшості компіляторів шаблонні файли повинні бути лише заголовками, оскільки компілятор може запускати основний процес компіляції лише тоді, коли надаються параметри типу, а для повного компіляції та оптимізації компілятор повинен бачити "обидва відразу" - код бібліотеки плюс шаблон значення параметрів. Це унеможливлює (або принаймні важко) створювати будь-які «заздалегідь складені» збірники для такої бібліотеки.


6
Отже, коротко кажучи, бібліотеки, що містять лише заголовки, зручніші , ніж ефективніші ; а оскільки C ++ не має стандартного менеджера пакунків, це допомагає керувати прийняттям.
Матьє М.

6
@MatthieuM: ні, компільований код дійсно іноді може бути більш ефективним, а для шаблонів шаблонів дизайн лише заголовка, як правило, не є питанням зручності. А збільшений збірний час, безумовно, не зручніший.
Док Браун

Якщо гарячий код у заголовках дійсно може призвести до більш ефективного компільованого коду, однак для цього не потрібно мати весь код у заголовках і, отже, не залежно від IMHO від бібліотек, що мають лише заголовки.
Матьє М.

1
@MatthieuM .: це, безумовно, правильно, але я вважаю, що термін "зручніший" не дуже добре описує випадок.
Док Браун

3
Я працював над великим вбудованим проектом над зменшеною, старшою ОС для свого попереднього роботодавця, і в тих випадках я можу засвідчити біль тривалих часів компіляції. Кожен, хто потрапив занадто багато начинок у файли заголовків, буде розглядатися нещадно.
Фред Томсен

15

Що ж, давайте спочатку знесемо деякі ваші припущення:

  1. Однією з переваг бібліотек, призначених лише для заголовків для C ++, є те, що їх не потрібно складати окремо.

Складати речі окремо означає, що потенційно не потрібно перекомпілювати все, якщо змінюється лише частина.
Отже, недолік замість переваги.

  1. В C і C ++ вбудований має сенс лише у тому випадку, якщо функція визначена у файлі заголовка *.

Так, єдиний ефект, inlineщо залишився, - це виняток із правила однозначення .
Горе вам, якщо ці визначення хоч інакше відрізняються.

Отже, якщо функція є внутрішньою для одиниці компіляції, позначте її static. Це також робить вкладку більш імовірною, оскільки функція повинна бути доступною, щоб вбудувати її.
Але все ж, погляньте на оптимізацію зв’язку та часу, яку підтримують принаймні MSVC ++, gcc та clang.

  1. Традиційно в C, .c / .h використовується макет, де заголовок представляє мінімальний публічний інтерфейс блоку перекладу. Аналогічно .cpp / hpp.

Ну, лише представлення мінімального інтерфейсу, безумовно, одна з цілей - досягти вищої стабільності API та ABI та мінімізувати час компіляції.

Тим більше, що класи C ++ насправді не орієнтовані на це, оскільки всі приватні біти просочуються до заголовка, як і захищені, чи потрібно виходити з нього чи ні.

Конструкторська схема PIMPL призначена для зменшення таких деталей.

Частина, де розділення інтерфейсу та реалізації повністю провалюється в C ++, - це шаблони.
Комітет намагався зробити щось із експортованими шаблонами , але це було відмовлено як занадто складне і не дуже працює.

Зараз вони працюють над належною модульною системою , хоча це відбувається повільно. Це суттєво скорочує час збирання, а також повинно підвищити стабільність API та ABI за рахунок зменшення їх поверхні.

Чи в основному бібліотеки, що мають лише заголовки, більш ефективні для коду та часу виконання, ніж традиційні верстки? Якщо так, то це через обширних вкладених чи інших оптимізацій?

Бібліотеки, призначені лише для заголовків, можуть бути ефективнішими за розміром коду та часом виконання, хоча це залежить від того, чи поділяється бібліотека, яка кількість її використовується, якими способами та чи вбудована докаже вирішальну перемогу в конкретному випадку.

А причина для вбудовування настільки важлива для оптимізації не тому, що саме вбудовування є таким великим стимулом, а завдяки можливостям для постійного поширення та подальшої оптимізації воно відкривається.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.