C++ Coding Guidelines
Our recommendations for creating and maintaining reliable C++ scientific software.
Good default choices
Here are our suggested default choices for build systems and third party libraries, which are all widely used and well supported:
- Version control: GitHub
- de facto standard for open source software
- start from our C++ template repository
- private repos also available
- Build system: CMake
- de facto standard for C++
- widely used and supported
- cross-platform
- Have a look at our dedicated CMake recommendations
- Testing framework: Catch2
- simple to setup and to use
- Continuous Integration: GitHub Actions
- well integrated with Github
- Documentation: Doxygen
- de facto standard for C++ documentation generation
- C++ Standard: 11 (or higher)
- many third party libraries now require this as a minimum
For each choice there are of course many alternatives, each with their pros and cons, but these represent a sensible default choice for the vast majority of C++ projects.
Our C++ Project Template is a simple way to
start a new C++ project with all of the above already set up - just click on the green Use this template
button.
If you are looking for more features such as python bindings, or alternative CI or git hosting providers, see our C++ Project Cookiecutter.
Tooling
Good tools make it easier to develop good code. Unlike the previous section, where a single choice must be made for the project, each person contributing to a project can use whichever tools they prefer. Some recommendations:
- IDE
- Visual Studio Code: free
- CLion: paid (but offer free academic licenses)
- CodeBlocks: free
- Code formatting
- Don’t do this manually, and especially don’t spend time debating how code should be formatted!
- Just pick a tool that does it automatically (e.g. your IDE, or clang-format)
- pre-commit and pre-commit.ci is a great way to do this
- Sanitizers Sanitizers are compiler tools that enable runtime checks for specific aspects of a program, e.g., thread-safety, memory management, undefined behavior and others. These sanitizers can be enabled at compile time, and will run alongside the compiled program and detect and report suspicious behavior. This comes with a performance penality that depends on the sanitizer used, hence they should not be enabled in production builds. To get the best reports, make sure you compile a symboliced binary. Available sanitizers differ from compiler to compiler:
- Package managers
- Debugging, Profiling and Benchmarking
There is a plethora of solutions for different platforms and use cases
- Google Performance Tools CPU and Memory profiling
- Nvidia Nsight for CUDA code
- Valgrind Instrumentation suite that includes heap- and cache-profilers as well as memory debugging tools
Recommended third party libraries
It is nearly always better, where possible, to use a well tested and maintained third party library instead of rolling your own solution to a problem. Typical benefits include: less bugs, better performance, less maintenance. Wherever possible, one should use the C++ standard template library (STL) and only use third-party dependencies when the STL does not suffice.
Here are our recommendations for third party libraries to solve some common problems in scientific computing:
- Vector/Matrix algebra: Eigen
- use case: multiply matrices, invert matrices
- allows you to write simple, expressive code
- high performance results
- Logging: spdlog
- use case: log messages / debugging information to the terminal / to a file
- simple to setup and to use
- String formatting: fmt
- use case: formatting strings, e.g. replacing
printf
calls - simple python-like interface, fast performance
- use case: formatting strings, e.g. replacing
- General purpose libraries that augment the STL with a wide array of functionality:
- Cross-language hierarchical data storage:
- Fast, cross-language tabular data storage: