C++ Project Conventions
There is nothing groundbreaking here. For legacy projects, make sure your style is consistent with the existing code; for new projects, follow the team’s style; and for projects without explicit requirements or for personal projects, keep the style consistent throughout.
My Style
I recommend the Google C++ Style Guide, which is quite comprehensive; at least, I have not found a Microsoft guide that is as thorough.
This is not a detailed discussion of specific rules. Instead, here are a few recommendations that the project as a whole may want to consider following:
For executable projects of up to ten thousand lines (not an exact figure), whether to use namespaces and whether to split the code into
includeandsrcdirectories are not important. At this scale, doing so will not provide much benefit and will instead add complexity.Once the amount of code exceeds this scale, however, try to follow this structure to ensure that continued growth does not lead to conflicts.
Note that you should estimate in advance whether the project will remain under ten thousand lines of code. If it might exceed that threshold, it is best to establish this organization early; otherwise, making the change later is effectively a refactoring.
For all library projects, use namespaces and organize the project into
includeandsrcdirectories.You need to consider the potential for naming conflicts when the library is used by a large project. Also, to make it convenient for other projects to include the library in source form, put the public interface header files in the
includedirectory. Unrelated header files must not be placed there, so that implementation details are not exposed and misused.
Additional Notes
Everything above is a recommendation. Follow it when practical; otherwise, as stated at the beginning, prioritize the existing style.
As the Google C++ Style Guide says:
We believe the current goals of the style guide are as follows:
Style rules should have an impact.
A style rule should provide a sufficiently large benefit to be worth remembering for every engineer. The benefit is relative to the current state of the codebase, so even if a habit is particularly bad, the benefit of prohibiting it is still small if people rarely use it. This explains why we have not written down certain rules. For example, the
gotostatement violates many principles, but it is now rarely seen, so the style guide does not discuss it. Optimize for the reader, not the author. Our codebase (and every component in it) is expected to exist for a long time. Therefore, we spend more time reading code than writing it. We explicitly choose to optimize the experience of average software engineers reading, maintaining, and debugging code rather than the comfort of writing it. “Leave clues for the reader” is one aspect of this philosophy. When code contains a special case (such as a transfer of pointer ownership), leaving a written hint for the reader at that point is valuable (usingstd::unique_ptrin the code clearly expresses the transfer of ownership).Be consistent with existing code.
By keeping the style of the codebase consistent as a whole, we can focus on other (more valuable) problems. Consistency also helps automation: tools that format code or adjust
#includeorder can work correctly only when your code meets expectations. Often, rules intended to “keep things consistent” essentially mean “pick one and stop wasting energy”; in such matters, the cost of arguing exceeds the value of providing freedom. The consistency principle also has limitations. It is a good tie-breaker when there is no clear technical rationale or long-term direction. This principle is best applied locally (within a file or a closely related group of interfaces). Do not adopt an old style and ignore the benefits of a new one merely for the sake of consistency. Keep in mind that a codebase may transition to a new style over time.Be consistent with the broader C++ community when appropriate.
Consistency with other organizations is valuable for the same reason that internal consistency is valuable. If a feature in the C++ standard solves a problem, or a paradigm has been widely adopted, that is a basis for adopting it. However, standard features and paradigms sometimes have flaws or were not designed with the needs of our codebase in mind. In such cases (as described below), those standard features should be restricted or prohibited. Sometimes we prefer an in-house library or a third-party library to the C++ standard library. Generally, this is because the library we chose is superior, or because the value of migrating to the standard library does not justify the required effort.
Avoid syntax that is unusual or dangerous.
Some C++ features are more unusual or dangerous than they appear on the surface. Some restrictions in the style guide exist to prevent people from falling into these traps. You need to meet a very high standard to receive an exemption from these restrictions, because ignoring them is very likely to directly cause program errors.
Avoid syntax that average C++ programmers would find tricky or difficult to maintain.
Some C++ features add complexity to code and are therefore generally unsuitable. In widely used code, we can accept more sophisticated syntax. This is because the benefits of a complex implementation are amplified by its many users, and because people writing new code do not need to reinterpret that complexity. When in doubt, you can ask the project lead for an exemption from these rules. This is essential for our codebase because code owners and team members change: even if everyone modifying this code today understands it, people may not understand it a few years from now.
Keep our scale in mind.
We have hundreds of millions of lines of code and tens of thousands of engineers, so one engineer’s mistake or shortcut can become a burden for many people. For example, be sure to avoid polluting the global namespace: if everyone puts things in the global namespace, it becomes difficult to avoid symbol collisions across hundreds of millions of lines of code, and difficult to fix those conflicts.
Make room for optimization when necessary.
Even when performance optimization techniques conflict with other principles in this document, those techniques are sometimes necessary and appropriate.
The purpose of this document is to provide the greatest possible degree of guidance along with reasonable restrictions. As always, you should follow common sense and ordinary good taste. Here we specifically mean the conventions established by the entire Google C++ community, not the preferences of you personally or of your team. You should remain skeptical and cautious about clever or unusual syntax: it is not the case that “anything not expressly forbidden is allowed.” Use your judgment. If you are unsure, do not hesitate to consult the project lead at any time.