Qingyu's blog

By Qingyu, 3 months ago, In English

As you might have heard, in the newest version of GCC, <cassert> is no longer included by <bits/stdc++.h> (you can view the change here). This means that the following code will now fail to compile:

#include <bits/stdc++.h>

int main() {
    assert(1);
}
Compilation Result

I noticed this issue during a recent compiler update on QOJ, where it broke a large number of older submissions. Because of this, I have reverted the compiler back to GCC 15.2.0 for now.

Of course, this is not the first time that a compiler or language-standard update has broken older code. However, I found this change seems to affect much more existing submissions than previous ones. Although GCC 16 was only released a few months ago and probably will not affect most contests immediately, platforms will eventually upgrade to newer GCC versions. I wanted to bring this issue to your attention and, in particular, hear your comments and suggestions.

  • Vote: I like it
  • +339
  • Vote: I do not like it

»
3 months ago, hide # |
Rev. 2  
Vote: I like it +44 Vote: I do not like it

Since bits/stdc++.h is not a standard header, could the include directory of the compiler used by the online judge be modified, like AtCoder did when adding AC-Library, so that cassert is included again in that header?

»
3 months ago, hide # |
 
Vote: I like it +14 Vote: I do not like it

What a BS, whose life will be improved by this change?

  • »
    »
    3 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it +18 Vote: I do not like it

    Primary purpose of bits/stdc++.h is that of a precompiled header, or a header unit, that is of things that you compile once, and any repeated compilation would use the cache instead of doing everything again.

    Using it properly makes compilation time of CP-grade programs near-instant, but in the case of cassert specifically, the issue is that whether assert actually does anything is controlled by NDEBUG compilation flag, as it should only work in debug builds, and not in release.

    Because it's a compilation-time control, as the commit message suggests, cassert is not suitable to be a part of bits/stdc++.h when it is used properly as a precompiled header or a header unit.

    • »
      »
      »
      3 months ago, hide # ^ |
       
      Vote: I like it +10 Vote: I do not like it

      I don't understand around 90% of words that you used in your comment, so I won't comment on the main issue, but I'll inquire about "Using it properly makes compilation time of CP-grade programs near-instant". What makes for a proper usage of it? What is "near-instant" in seconds? Whenever I compile my cp codes it always takes a few seconds, which I'd hardly call "near-instant", but maybe it can be called like that given that this header theoretically includes a ton of things?

      • »
        »
        »
        »
        3 months ago, hide # ^ |
        Rev. 2  
        Vote: I like it +8 Vote: I do not like it

        The reason why you aren't noticing a difference is likely because you aren't using a precompiled version of the header file (which would end with .gch if compiling with gcc). Precompiled headers take out a good chunk of the work (especially for something as large as bits/stdc++.h which usually takes >1s) because, as the name implies, they have already been compiled; you don't need to recompile them each time. Some useful resources are below.

      • »
        »
        »
        »
        3 months ago, hide # ^ |
         
        Vote: I like it +8 Vote: I do not like it

        See his link about precompiled headers. You don't use precompiled headers when you compile your cp codes, you just include headers as normal. In order to use one, you'd have to precompile it on your system first.

        I tested it out of curiosity and a blank main with #include "bits/stdc++.h" goes from 2 seconds to 0.6s on my system when I precompile it. For complex programs it's going to vary.

      • »
        »
        »
        »
        3 months ago, hide # ^ |
         
        Vote: I like it +33 Vote: I do not like it

        Proper usage is to actually precompile it as a .gch file or a module, and tell compiler to use it.

        I think this GCC page provides a nice usage example with modules:

          g++ -fmodules -x c++-system-header -c bits/stdc++.h
          g++ -fmodules -include bits/stdc++.h mycode.C
        

        You do this (add your custom compilation flags to both commands), and then it's realistic to reduce compilation time from ~2s to 0.2s-0.5s. You may need to use -fmodules-ts instead of -fmodules, or use precompiled header approach (see below), depending on your GCC version.

        Legacy way to do it is to locate stdc++.h file in your system, and apply g++ to it directly (without module flags, just same command as for your main file), and it will produce stdc++.h.gch file. You can leave it in system include path, or drop it in your code folder, and it should produce the same effect (and is sometimes more stable). You may need to add -include stdc++.h to your command.

        If in doubt, you can use -H, aka --trace-includes, to verify whether the compiler actually used it as a precompiled header, or it still includes all individual headers one by one.

»
4 weeks ago, hide # |
 
Vote: I like it -38 Vote: I do not like it

Oh no.It means that I should write a another #include when I want to use assert.