C++ Style Comparison: Google Style Guide vs CppCore Guidelines #657
AlexanderLanin
started this conversation in
Operational Community
Replies: 1 comment
-
|
@AlexanderLanin should we follow up on this? |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Intro
We'll follow MISRA, that's not the question here. The core guidelines is an alternative to MISRA (no judgement here), however that's not the point of this comparison. Here I want to focus on "style" only. Whatever "style" means.
I'll attempt to map the guidelines and highlight the differences.
No idea whether that will work out or not.
References
Mapping
We'll use the categories from the Google Style Guide, as they provide a clearer structure.
Caution
The following is provided by ChatGPT. ChatGPT can make mistakes. Check important info.
#defineGuard (header include guards)#includeguards for all .h files” (SF: Source files – C++). Also advises making guard unique (e.g. include project/component in macro) (SF: Source files – C++).PROJECT_PATH_FILE_H_).""for project headers and<>for others (SF.12 (SF: Source files – C++)) and to include headers before other declarations (SF: Source files – C++). No fixed global->local order rule, but consistency is advised.using namespaceat global scope in headers (SF.7 (SF: Source files – C++)). All code should be in namespaces (exceptmainor special cases).using namespace(e.g., MISRA C++ 2008 Rule 7-3-4 forbids unnamed namespaces in headers and Rule 7-3-5 forbids using-directives in headers (Guidelines for the use of the C++14 language in critical and safety-related systems)). Code is expected to be organized into namespaces (to avoid name collisions).using namespaceat global scope. (Unnamed namespaces for internal linkage are allowed in .cpp, but not in headers.)staticor unnamed namespace is recommended for internal linkage.staticor unnamed namespace) in implementation files, to avoid polluting global namespace and prevent ODR violations.thread_local. They implicitly allowthread_localusage. Best practice in core/C++ is thatthread_localobjects follow the same rules as other static-duration objects regarding initialization (const-initialized if possible). Core would expectthread_localto be used judiciously (e.g., for POD types or with constant initialization to avoid surprises).thread_local(which is a C++11 feature). AUTOSAR emphasizes that any static-duration object (includingthread_local) should have deterministic initialization. There is an expectation (not a formal rule) to initializethread_localvariables with constant expressions to avoid dynamic initialization issues at runtime, in line with Google’s rule.thread_localinit – Google requiresthread_localvariables to be initialized with a compile-time constant (prevent dynamic init) (Google C++ Style Guide). Core/AUTOSAR do not explicitly call this out, but implicitly prefer static-duration objects (including thread_local) to have constant initialization for safety. No direct conflict – more of a Google-specific emphasis.explicit)explicit” (C: Classes and class hierarchies – C++) (C: Classes and class hierarchies – C++). Core also requires conversion operators to be marked explicit (in C++11 and above) unless truly intended to be implicit. This matches Google’s rule to not allow implicit conversions.explicit(Guidelines for the use of the C++14 language in critical and safety-related systems). In practice, AUTOSAR insists onexplicitfor single-parameter ctors to prevent unintended conversions.explicit– All enforce using theexplicitkeyword for single-argument constructors and conversion operators to avoid unintended implicit conversions (Google C++ Style Guide) (C: Classes and class hierarchies – C++). (Copy/move constructors are exceptions and remain non-explicit.)structfor passive data objects)structvsclass. They note thatstructandclassdiffer only by default access. However, the intent (as per C++ community practice) is similar to Google’s: usestructfor simple data aggregates with public data and no invariants, and useclassfor types with invariants or complex behavior. (This isn’t an explicit Core rule, but it’s a common guideline consistent with Google’s.)structorclassbased on content. It treats them interchangeably except for access control. Typically, AUTOSAR code will useclassfor most user-defined types (with appropriate access specifiers), but this is not a strict rule. There is no prohibition on usingstructfor POD types; it’s left to project style.structvsclass– Google explicitly says to usestructonly for plain data holders (all-public, no invariants) (Google C++ Style Guide) (Google C++ Style Guide). Core/AUTOSAR do not have a formal rule, but generally agree in spirit: if an object has no invariants and is just data,structis acceptable. (It’s a matter of style; not enforced outside Google.)std::pair/std::tuple)std::pairorstd::tuple. (In the community, it’s advised to usepair/tupleonly for very short-lived or obvious cases; otherwise define a struct.) So core’s philosophy aligns, though no explicit rule text.std::pairorstd::tuple. (AUTOSAR does allowstd::pairandstd::tuplesince they are part of C++14, but expects judicious use.)std::pairorstd::tuplefor readability (Google C++ Style Guide). Core and AUTOSAR have no formal rule, but generally value clarity – using a struct with descriptive member names is usually recommended for maintainability (especially in long-lived or widely used interfaces).override. These match Google’s points (only use public inheritance for true is-a, minimize multiple/base classes).finalappropriately; core has similar guidance with theoverridespecifier.)because you can’t replicate short-circuit or sequencing semantics). **C.162**–**C.168** cover overloading conventions (e.g., if you overload==, also overload!=, etc.). They align with Google’s note to overload operators judiciously and only in intuitive ways ([Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html#:~:text=Operator%20Overloading)) ([Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html#:~:text=,may%20require%20a%20search%20tool)). Core also discourages user-defined literals in most cases (no specific rule, but they are rarely used in the standard library except for suffixes like_s` etc.).stringandconst char*is fine, but if semantics differ, use different function names. (This is in line with Google’s rule, though core doesn’t have a single rule number for it – it’s general advice.)auto func() -> Type)decltype. For typical functions, AUTOSAR code usually uses the conventional return type syntax, aligning with Google’s advice to prefer the ordinary syntax unless trailing form is clearer.-> Typesyntax should be used only when it improves readability (e.g., in complex template situations or for lambda declarations) (Google C++ Style Guide). No guideline forbids it – it’s a matter of clarity. Google explicitly advises against overusing trailing returns, which is consistent with general practice.const T&or value, and using pointers or references only for in-out parameters, which mirrors Google’s rules for parameter passing (inputs by value or const-ref, outputs as pointer or returned) (Google C++ Style Guide) (Google C++ Style Guide).const&(and usestd::optionalif an input is optional), outputs should ideally be returned or, if multiple outputs, passed as pointers (which can be null to signify “unused”) (Google C++ Style Guide). This makes it clear at call sites what is an out-param. Google’s specific guidance on using pointers for optional outputs is consistent with AUTOSAR practices.noexcept(use of noexcept specifier)noexceptfor functions that are not supposed to throw. For example, move constructors/assignments should benoexcept(C.66). They caution thatnoexceptshould reflect true no-throw guarantees. This aligns with Google’s advice to mark functionsnoexceptwhen they won’t/can’t throw (especially important in exception-enabled code for optimization) (Google C++ Style Guide) (Google C++ Style Guide).noexceptfor functions that are guaranteed not to throw (since AUTOSAR allows exceptions,noexcepthelps optimizations and clarity). There’s an AUTOSAR rule (A15-3-3) that destructors should be noexcept by default, and recommendations to declare move constructorsnoexcept. No conflict here with Google, which also suggests noexcept where applicable (even though Google’s code typically doesn’t throw, they use noexcept for things like move ops).noexceptusage – All agree on usingnoexceptfor functions that are meant not to throw (particularly special member functions like moves) (Google C++ Style Guide). Google notes it’s hard to guarantee in exception-disabled builds, but still encourages marking functions noexcept for clarity/performance. Core and AUTOSAR, working with exceptions, explicitly usenoexceptto enable optimizations (e.g., in containers) and to denote non-throwing functions.dynamic_cast,typeid)dynamic_cast/typeidhave legitimate uses (when type-safe downcast is needed), but suggest alternatives like visitor pattern or virtual functions first. This is less strict than Google’s “avoid RTTI” stance (Google C++ Style Guide) (Google C++ Style Guide).dynamic_castin safety critical code. The AUTOSAR guidelines say RTTI “is prone to abuse” and should be avoided. It permits it only in test or very controlled scenarios. This is very close to Google’s rule to avoid RTTI (Google C++ Style Guide) (Google C++ Style Guide). (If RTTI-like behavior is needed, AUTOSAR would prefer alternative designs as well.)dynamic_castwhen necessary (they consider it a tool for specific cases). AUTOSAR is closer to Google here: RTTI is essentially forbidden in high-integrity code. Summary: Google/AUTOSAR disallow or strongly discourage RTTI; Core allows it with caution.static_cast,const_cast,reinterpret_castas appropriate, and prefer avoiding casts overall if possible. This matches Google’s rule to use C++-style casts (and brace-initialization for numeric conversions) (Google C++ Style Guide) (Google C++ Style Guide). Core also mentions usinggsl::narrowor similar for narrowing conversions (Google uses brace-init to catch narrowing).static_cast/dynamic_cast/reinterpret_cast/const_castinstead of C casts. AUTOSAR additionally states that casting away const or downcasting should be done carefully (or not at all). Google’s recommendations (use C++ casts and only when necessary) line up exactly.static_cast/const_castetc. for explicit conversions (Google C++ Style Guide) (Google C++ Style Guide). They also agree on using brace initialization for safe numeric conversions (Google explicitly says so (Google C++ Style Guide), Core/AUTOSAR concur in principle on avoiding unchecked narrowing). Overall, casting is to be done in a controlled, explicit manner in all standards.<<with non-standard semantics, and don’t expose internal state in operator<< – these align with general best practice rather than explicit Core rules.) Core’s focus is more on not usingprintfin modern C++ when streams suffice, which is implicitly aligned with Google.<iostream>, but in practice, heavy use of iostreams in embedded/safety code is rare (due to performance and determinism concerns). AUTOSAR guidelines don’t forbid it for debugging or logging. Google’s advice to keep streaming simple (only user-visible content, no complex hidden side effects) is generally good practice and would be expected in AUTOSAR code if streams are used.<iostream>for logging/debug output and simple formatting, and cautions to keep overloaded<<operators straightforward (only output user-visible state) (Google C++ Style Guide) (Google C++ Style Guide). Core/AUTOSAR have no contrary rules – they accept iostreams as standard. (AUTOSAR developers may limit iostream use for performance, but that’s contextual.) All agree that if you do overload output operators, do so in an unsurprising, simple way.constexpr,inline, templates, etc. instead of#define. If macros are needed, they suggest naming them ALL_CAPS (and possibly with a project-specific prefix to avoid collisions) (SF: Source files – C++). This is fully in line with Google’s rule (which also requires a project prefix on macro names and discourages macro APIs) (Google C++ Style Guide) (Google C++ Style Guide).inlineorconstinstead) (Guidelines for the use of the C++14 language in critical and safety-related systems). This completely aligns with Google: macros are last resort (and must be all-caps with meaningful prefixes when used).autoonly when it aids clarity)autoto avoid repetition, but with judgement. They state to useautowhen the type is obvious from context or unimportant to the reader (Improving Stability with Modern C++, Part 3 — The auto Keyword). This is similar to Google’s rule of using type deduction only if it makes code clearer or safer, not just to save typing (Google C++ Style Guide) (Google C++ Style Guide). Core might endorseautoslightly more (to avoid long type names), but they also warn against cases where it hinders understanding. Overall, the philosophy is the same; the emphasis differs slightly.auto. It can be used (C++14). The AUTOSAR/MISRA view is thatautois fine if it does not impair code clarity. Tools in safety-critical projects might flag overuse ofautoif it obscures types. In practice, AUTOSAR code usesautoin obvious situations (iterators, lambdas) but not in cases where the type’s meaning isn’t clear. This practically aligns with Google’s guidance.autodeduction – All agree thatautoshould be used with caution. Use it when it makes code cleaner (eliminating noise or obvious redundancy) (Google C++ Style Guide), but not when it would make the code less readable to someone unfamiliar. Google explicitly says not to useautojust to avoid typing a type name (Google C++ Style Guide). Core/AUTOSAR share that intent – they allowauto, but expect developers to maintain clarity.std::make_uniquewas preferred pre-C++17, but CTAD for smart pointers isn’t available. Core hasn’t flagged CTAD as problematic.) Thus, Core is more permissive whereas Google says only use CTAD when the template author explicitly intended it (to avoid surprises).make_uniqueor providing explicit template args. Google’s rule effectively prohibits CTAD unless guaranteed safe – but AUTOSAR outright cannot use it until they update to C++17 or later (not within AUTOSAR C++14 guidelines).mutableonly if needed, and not to copy mutable data inadvertently – generally consistent with Google’s best practices on lambdas.[&]captures can be dangerous if the lambda is called later (e.g., on another thread). The recommendation is to capture only what you need, by value where possible – consistent across all..hfor headers and.cppfor implementation files by default (SF: Source files – C++) (SF: Source files – C++), but also say consistency in a project is more important than the specific extension. Google uses.hfor headers and.ccfor sources. This is a minor difference in convention (Google’s use of.ccvs “.cpp” is just a style choice). Core and Google both agree filenames should be all lower-case. Core doesn’t mention underscores vs dashes explicitly, but consistency is implied..h,.hpp, or.hxx(Guidelines for the use of the C++14 language in critical and safety-related systems) (and expects consistency). Source files typically use.cfor C and something like.cppor.cxxfor C++ (AUTOSAR doesn’t mandate one, but.cppis common). Google’s preference for.ccis not used in AUTOSAR contexts (not a technical issue, just convention). Filenames in AUTOSAR are also lower-case (often with underscores)..ccvs.cpp), which is a matter of project style – marked partial but it’s a trivial convention difference.MyTypeNamevs a core-guidelines style ofmy_type_nameis a stylistic clash. Core acknowledges that naming style is arbitrary but requires consistency – their examples (e.g., in guidelines and STL) tend to use lower-case types.MyConcreteClass(PascalCase). Core: tends towardmy_concrete_class(following STL conventions) – or at least Core doesn’t insist on PascalCase. AUTOSAR is agnostic but often follows general C++ trends. This is primarily a style divergence: Google’s style guide and many internal codebases use PascalCase for types, whereas the C++ Core Guidelines favor a more STL-like all-lowercase approach.std::integral). It’s likely core would recommend following the standard’s convention for concepts (i.e., snake_case). Thus, Google’sSameAsvs. core’s expectedsame_asis a conflict in naming style.Sortable), treating them as types. This differs from the standard library and likely core style, which use snake_case (e.g.,sortable) for concepts. AUTOSAR currently doesn’t support concepts at all (C++14), so any usage is non-compliant. In summary, Google’s concept naming style doesn’t match the lower_case style that core/standard favor, and AUTOSAR can’t use concepts in its current standard.snake_casefor variables (Google C++ Style Guide). Core Guidelines also prefer lowercase (likely snake_case) for variable names – this aligns. The difference: Google requires a trailing underscore for class data members (foo_for a member vsfoofor a local) (Google C++ Style Guide) (Google C++ Style Guide). Core Guidelines do not mandate a member naming convention like trailing underscore; they leave it to project style. Some core-guideline-following projects might usem_or no prefix at all. So the general casing aligns (lowercase), but the member suffix is a Google-specific convention.mVariableor_variableor no notation, depending on legacy or team preference. Google’s trailing underscore for private members is not universally practiced in AUTOSAR space. However, this is just an naming style detail. The basic lowercase underscore style is common ground.lower_case_with_underscoresfor variable names. Google adds a_suffix for class data members (to distinguish them) (Google C++ Style Guide). Core/AUTOSAR don’t require that, though it’s allowed. So, naming case is aligned (snake_case), but the member-variable underscore suffix is a Google-specific style.constexprorconstvariables)k(e.g.,kMaxValue) (Google C++ Style Guide). Core Guidelines do not prescribe this convention. In fact, Core suggests that macros be ALL_CAPS and other constants follow normal variable naming (or use uppercase only if they are immutable and want to distinguish, but this is not in the guidelines explicitly). The STL and most C++ code do not use akprefix for constants. Thus, Google’s constant naming (sometimes called “Hungarian-ish” by others) is a unique style.constexpris available, they might just treat it as a variable. There is no single rule – just be consistent. Google’skNamestyle is not required in AUTOSAR, but it’s not harmful either. It’s simply different.kprefix (e.g.,kBufferSize) for constants and constexprs that have static storage duration (Google C++ Style Guide). Core/AUTOSAR do not use this convention (they either use ALL_CAPS for macros or just treat constant variables like other variables). This is a stylistic conflict – Google’s convention vs others. (All agree these constants should beconst/constexprand not macros; only the naming differs.)DoSomethingImportant()(CapitalizedCamelCase) (Google C++ Style Guide) (Google C++ Style Guide). Core: tends towarddo_something_important()(lower_case). AUTOSAR: no enforced rule, but many codebases use lower_case or mixedCase for functions. So, Google’s function naming convention is a different style from core’s default and some AUTOSAR practices. This is a pure naming-style difference (no functional impact).my_project::sub_module) (Google C++ Style Guide), which is common practice and not contradicted by core or AUTOSAR.diagnosticorcalibration. This matches Google’s requirement. Underscores in namespace names are also acceptable if needed (AUTOSAR doesn’t forbid it).kEnumNamestyle (Google C++ Style Guide) (for scoped and unscoped enums). Core Guidelines don’t have a stated convention, but the prevailing style in modern C++ is to treat enumerator names as scoped members, often lowercase (especially forenum class). The standard library’s fewenum class(likestd::endian) use enumerators likelittleandbig(lowercase). Core’s NL.9 says ALL_CAPS only for macros, implying they wouldn’t use leadingkor all-caps for enum values – probably just treat them as regular names (possibly PascalCase without thekor just lower_case). In any case, Google’s prefixedkNameis unique to their style.enum class, that practice is less necessary. AUTOSAR hasn’t mandated thekprefix. Some AUTOSAR code might use ALL_CAPS for unscoped enum values to distinguish them. In scoped enums, they might use PascalCase or lower_case. There isn’t a single rule; it’s typically project-defined. Google’s approach differs (they don’t use ALL_CAPS, but usek+ CamelCase which is distinct).kEnumValuenaming (Google C++ Style Guide), which differs from many other code standards. Core/AUTOSAR don’t prescribekor all-caps for enum values – styles vary (older code uses ALL_CAPS, modern code often treats scoped enums like normal names). This is a naming convention conflict. (All agree enumerators should be constants – the difference is purely in notation: Google’s constant-style prefix vs. others’ conventions.)MYPROJECT_MY_MACRO. There’s no conflict here.FILE_NAME_H_or have a project prefix. Any function-like macros (which AUTOSAR tries to avoid) would also be all-caps. Google’s exampleMYPROJECT_ROUND(x)(Google C++ Style Guide)fits this perfectly.Beta Was this translation helpful? Give feedback.
All reactions