forked from project-asgard/asgard
-
Notifications
You must be signed in to change notification settings - Fork 0
coding standards
Tyler McDaniel edited this page Jan 7, 2020
·
5 revisions
This project aims to have maintainable code, and as such developers wishing to contribute code must make a non-trivial amount of effort to ensure that the code base remains as correct, understandable, and pleasant to work with as possible.
We are constantly revising and updating these standards for the ASGarD project. If you have suggestions on how to improve them, please feel welcome to open an issue
There are many resources available, but we generally try to follow community-wide best practices. Some good resources that C++ developers should in general be familiar with, are:
- ISO C++ Core Guidelines
-
C++ Best Practices
- Specifically, Style
Some specific choices that we want to highlight for the ASGarD project:
- naming conventions
- names are as descriptive as possible
-
snake_case
and notcamelCase
orCamelCase
- class names, variables, (including object instances) and class members start with lowercase
- compile-time constants, including template parameters are
ALL_CAPS
- private members begin with a single underscore e.g.
int _data_member
- avoid overloading terms, including from other domains
- East const (http://slashslash.info/eastconst/)
- hygiene
- avoid
using namespace ...
and minimizeusing
andtypedef
- use
assert()
as much as possible - prefer value semantics (prefer to pass and return by value)
- use rule of 5 to ensure proper move semantics
- use RAII and no raw pointers, no raw new(), no malloc() (these are buried as deeply into owning types as possible)
- use
auto
when appropriate, but not at the expense of understandability - avoid use of ifdefs especially, and preprocessor macros in general
- minimize use of
.data()
and obtaining unprotected access to memory - Simplest api possible - don't pass objects by rvalue reference when it doesn't provide a performance benefit, and when we do need to do that, make it clear in the function name that we are taking ownership.
- avoid
- structure
- source files are defined as components
- logical unit of functionality
- always 3 files:
component.hpp
,component.cpp
(even if empty),component_tests.cpp
- the component's header is always included first, skip a line, then the remaining includes are in alphabetical order
- pragma once all header files. prefer over include guards
- classes
- use
explicit
for non-converting constructors - in order:
public:
, thenprotected:
, thenprivate:
if present - in order: constructor(s), destructor, copy constructors, move constructors, operators, non mutators, mutators
- private members begin with a single underscore e.g.
int _data_member
- use
- variables are declared as close as possible to first use
- variables(/classes) are initialized(/instantiated) at declaration
- no return statements in constructors or void functions (unless returning early)
- minimize use of early returns
- Composition is easier to read and understand than inheritance, but functional input/output is easier to read and understand than either. Avoid superfluous classes, e.g. those that simply wrap a container.
- push details as far downward in the implementation as possible without repeating code or incurring unacceptable (measured) performance penalties.
- source files are defined as components
- avoid using C++ exceptions
- less confusion in (parallel) error code paths
- enable (possibly) more compiler/std optimizations
- avoid using C++ dynamic polymorphism (virtual functions / inheritance)
- difficult to combine with static polymorphism
- vtable difficulty in some accelerator runtimes / disjoint memory spaces
- prefer signed integers; do not use unsigned to represent non-negative quantities
- use
extern template
and explicitly-instantiated templates whenever possible to separate interface and implementation, reduce recompilation and binary size
- preface all project-specific variables with
ASGARD_
- use
option()
instead ofset(...CACHE...)
- always prefer
target_
versions of commands (e.g.target_include_directories()
) - include
PRIVATE
/INTERFACE
/PUBLIC
with alltarget_link_
and related commands - use generator expressions for more concise and robust checks, but balance with readability