Hello Std Proposals,

I have been benchmarking the cost of including the standard library headers alone without actually using anything in them. This is because it is common for large C++ programs to end up with headers that have massive include graphs that slow down compilation considerably. Even when the individual translation units use only a small fraction of what is included in them.

The executive summary is that the compile time costs incurred by using the standard library have roughly doubled between C++11 and C++23. Simply changing the standard library in use on the command line could add 0.5-1.0 seconds to the compile time for each file in your project. This is because of the surprising amount of additional code that gets included when you change language standards.

Even the cost of loading the standard library as a PCH has been going up and it could still add up to a considerable amount of time across hundreds of files.

I would like to strongly discourage adding more code to existing headers in future standards.

As for floating a proposal on this list, having things like <algorithm-core> that includes only the contents of <algorithm> as defined by C++11 would be a way to cut back. I can't say there are any clean and satisfying solutions that come to mind right now.

Here is the script I used to generate the following document if you want to check my methods: https://github.com/whatchamacallem/cxx-std-include-bench The script and the following documents are also attached to this email. 

Regards,
Adrian



Benchmarking Including The C++ Standard Library

All timings are the median of 51 runs. Timings collected on an MSI Stealth A16 AI+ A3XVFG.

This script measures the compilation overhead of including but not using a large set of the C++ standard library headers with GCC and Clang for C++11, C++14, C++17, C++20, and C++23. Nothing in the headers is actually used. Startup time is the time taken to compile an empty file with no includes at all and is deducted from all subsequent measurements. GCC uses libstdc++ and Clang uses libc++.

CompilerVersionStartup (ms)
GCCg++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.06
ClangUbuntu clang version 18.1.3 (1ubuntu1)15

Headers Under Test

These are C++11 headers that were chosen as representative of normal use in a large C++ program with a complex include graph. Choosing C++11 headers allows showing how they change across all language versions being tested.

<algorithm> <array> <atomic> <bitset> <chrono> <condition_variable> <deque> <forward_list> <fstream> <functional> <future> <iostream> <iterator> <list> <locale> <map> <memory> <mutex> <numeric> <queue> <random> <regex> <set> <sstream> <stack> <stdexcept> <string> <thread> <tuple> <typeindex> <unordered_map> <unordered_set> <utility> <valarray> <vector>

Compilation Time

Time taken to compile the selected standard library headers in an otherwise empty translation unit. Also lists the lines of code seen by the preprocessor for that translation unit. Times do not include compiler startup.

StandardGCC LOCGCC ms (net)Clang LOCClang ms (net)
C++117386035460612500
C++147565737061644527
C++178388045168122629
C++2010889981483963938
C++2311286586886602995

Compilation Time Using A Precompiled Header

Time to compile an empty translation unit that uses only a precompiled header (PCH) containing the selected standard library headers. The PCH is rebuilt for each version of the standard. Times do not include compiler startup.

StandardGCC PCH ms (net)Clang PCH ms (net)
C++115971
C++146481
C++177699
C++2023794
C++23238102

Lines Of Code Per-Header (GCC)

Lines of code seen by preprocessor when including each header individually. Each column shows the absolute LOC and the delta from the prior standard,

if any.

HeaderC++11C++14C++17C++20C++23
algorithm1075911302 (🔺543)12383 (🔺1081)21184 (🔺8801)23940 (🔺2756)
array56786132 (🔺454)6655 (🔺523)9944 (🔺3289)10473 (🔺529)
atomic34003461 (🔺61)3950 (🔺489)7767 (🔺3817)7920 (🔺153)
bitset1351814430 (🔺912)17834 (🔺3404)23084 (🔺5250)24116 (🔺1032)
chrono38664691 (🔺825)5233 (🔺542)60024 (🔺54791)61446 (🔺1422)
condition_variable1340914298 (🔺889)15020 (🔺722)39998 (🔺24978)41170 (🔺1172)
deque1009710975 (🔺878)13439 (🔺2464)18509 (🔺5070)19428 (🔺919)
forward_list80148892 (🔺878)11372 (🔺2480)16517 (🔺5145)17436 (🔺919)
fstream2174822654 (🔺906)26071 (🔺3417)31503 (🔺5432)32620 (🔺1117)
functional55626185 (🔺623)26147 (🔺19962)31571 (🔺5424)33415 (🔺1844)
future2453725785 (🔺1248)28081 (🔺2296)42231 (🔺14150)43412 (🔺1181)
iostream2007720983 (🔺906)24365 (🔺3382)29683 (🔺5318)30800 (🔺1117)
iterator1606416970 (🔺906)20349 (🔺3379)25582 (🔺5233)26607 (🔺1025)
list77658220 (🔺455)10701 (🔺2481)15850 (🔺5149)16769 (🔺919)
locale2121022116 (🔺906)25500 (🔺3384)30869 (🔺5369)31894 (🔺1025)
map1065111789 (🔺1138)13556 (🔺1767)18705 (🔺5149)19624 (🔺919)
memory1509415978 (🔺884)16785 (🔺807)36698 (🔺19913)37736 (🔺1038)
mutex78558794 (🔺939)9553 (🔺759)15850 (🔺6297)16758 (🔺908)
numeric19402733 (🔺793)4563 (🔺1830)7113 (🔺2550)7308 (🔺195)
queue1383214717 (🔺885)17136 (🔺2419)22246 (🔺5110)23195 (🔺949)
random2548126429 (🔺948)33162 (🔺6733)38388 (🔺5226)40628 (🔺2240)
regex4619147475 (🔺1284)50374 (🔺2899)56217 (🔺5843)57376 (🔺1159)
set909910191 (🔺1092)13268 (🔺3077)18417 (🔺5149)19336 (🔺919)
sstream2068921595 (🔺906)24977 (🔺3382)30514 (🔺5537)31631 (🔺1117)
stack1033911224 (🔺885)13585 (🔺2361)18663 (🔺5078)19603 (🔺940)
stdexcept1294413850 (🔺906)17232 (🔺3382)22478 (🔺5246)23502 (🔺1024)
string1247113377 (🔺906)16781 (🔺3404)22035 (🔺5254)23066 (🔺1031)
thread898310372 (🔺1389)11045 (🔺673)36539 (🔺25494)37711 (🔺1172)
tuple35903755 (🔺165)4275 (🔺520)11078 (🔺6803)11931 (🔺853)
typeindex178178 (🔺0)178 (🔺0)3570 (🔺3392)3625 (🔺55)
unordered_map1258913538 (🔺949)15287 (🔺1749)20639 (🔺5352)21558 (🔺919)
unordered_set1255313502 (🔺949)15166 (🔺1664)20522 (🔺5356)21441 (🔺919)
utility22242353 (🔺129)2812 (🔺459)4609 (🔺1797)4812 (🔺203)
valarray1526315806 (🔺543)20819 (🔺5013)29697 (🔺8878)33653 (🔺3956)
vector1084811726 (🔺878)14206 (🔺2480)19333 (🔺5127)20261 (🔺928)