hatcat / cg30_issues

The public issues repository for the book "Beautiful C++"
4 stars 1 forks source link

#pragma once instruction is theoretical, not practical #13

Open claremacrae opened 3 years ago

claremacrae commented 3 years ago

I strongly disagree with the absolute blanket instruction not to use #pragma once.

I recognise that it is what the core guidelines say, but believe that it is advice built out of theoretical ideals, and not real-world, practical experience that could be help read-world users.

The current text says nothing about the things that can go wrong with include-guards, and hence the resultant time-saving benefits of #pragma once

Real-world experience

I am far from alone in saying this: I have spent way, way too much time tracking down build errors which turned out to be 2 or more headers having the same include guard.

Many people will only ever need to build on multiple compilers that already support pragma once... and are not writing code that will be released to other people.

To impose on them the time-costs of editing and debugging include-guards is a purist attitude that does not recognise the costs of the imposition.

Explaining the problem to readers

If this instruction to use include guards remains in the book, the section should start by actually giving two code snippets, one that uses pragma once, and one that uses include guards.

It should then demonstrate the hazards of include guards, e.g. via a scenario of copying an existing file to make a new class... but forgetting to update the include-guard name in the copy.

Then showing code which includes both headers and uses both types...

And showing the type of the compiler error that you get when the second header file is not read. Where the obvious thing to do is to assume you got the class name wrong in the second-loaded file, so you spend ages trying to work out what is wrong with the class you created - and if you are lucky, it will only take you a few minutes to realise that the problem was the name of the include guard.

But if you are new to this category of error, it may take you a long, long time to understand the problem.

Better (IMO) advice

I think the advice should be "if your source code is released to people and needs to run on a wide variety of compilers, you will have to use include-guards, and this is why the core guidelines advocate for include-guards.

However, if you know that the compilers your organisation is using currently all support #pragma once, then you and your colleagues will have a more efficient development process if you use #pragma once.

If your organisation changes and you later find that you need to convert to include-guards, then you can use a scripting language such as python to make the one-off conversion, at the time that you know you need it. And teach your colleagues to use the more-error-prone, but more-widely-supported, approach.

Alternative approach

Some projects that release code as single-headers use #pragma once in their separate headers, so they get the time-saving and error-saving in the development process...

And then their release process that combines the source code in to a single header strips out the #pragma once and inserts a single include-guard around the combined file.

Examples:

https://stackoverflow.com/a/62218074