#pragma once
has unfixable bugs. It should never be used.
If your #include
search path is sufficiently complicated, the compiler may be unable to tell the difference between two headers with the same basename (e.g. a/foo.h
and b/foo.h
), so a #pragma once
in one of them will suppress both. It may also be unable to tell that two different relative includes (e.g. #include "foo.h"
and #include "../a/foo.h"
refer to the same file, so #pragma once
will fail to suppress a redundant include when it should have.
This also affects the compiler's ability to avoid rereading files with #ifndef
guards, but that is just an optimization. With #ifndef
guards, the compiler can safely read any file it isn't sure it has seen already; if it's wrong, it just has to do some extra work. As long as no two headers define the same guard macro, the code will compile as expected. And if two headers do define the same guard macro, the programmer can go in and change one of them.
#pragma once
has no such safety net -- if the compiler is wrong about the identity of a header file, either way, the program will fail to compile. If you hit this bug, your only options are to stop using #pragma once
, or to rename one of the headers. The names of headers are part of your API contract, so renaming is probably not an option.
(The short version of why this is unfixable is that neither the Unix nor the Windows filesystem API offer any mechanism that guarantees to tell you whether two absolute pathnames refer to the same file. If you are under the impression that inode numbers can be used for that, sorry, you're wrong.)
(Historical note: The only reason I didn't rip #pragma once
and #import
out of GCC when I had the authority to do so, ~12 years ago, was Apple's system headers relying on them. In retrospect, that shouldn't have stopped me.)
(Since this has now come up twice in the comment thread: The GCC developers did put quite a bit of effort into making #pragma once
as reliable as possible; see GCC bug report 11569. However, the implementation in current versions of GCC can still fail under plausible conditions, such as build farms suffering from clock skew. I do not know what any other compiler's implementation is like, but I would not expect anyone to have done better.)